Go语言基于TCP实现简易聊天工具的示例代码
本文演示如何使用 Go 语言标准库中的 net 包构建一个基于 TCP 协议的简易命令行聊天工具。主要包含服务端(Server)与客户端(Client)两部分代码,涉及 TCP 监听、接受连接、goroutine 并发处理以及基础的网络 I/O 操作,旨在帮助开发者理解 Go 在网络编程中的基本工作流。
核心原理与结构准备
该聊天工具采用 C/S(客户端/服务器)架构。服务端负责监听指定端口并等待客户端接入,每当有新连接建立时,便启动一个新的协程(goroutine)来单独处理该连接的读写交互。客户端则负责向服务端发起连接,并在终端中循环输入与显示消息。
第1步:服务端代码实现 (server.go)
目的: 启动 TCP 监听服务,接收客户端连接并处理双向通信。
关键组件:
- net.Listen: 创建 TCP 监听器。
- listen.Accept: 阻塞等待直到有客户端连接。
- go process(conn): 使用协程并发处理每个连接,避免阻塞主循环。
- bufio.NewReader(os.Stdin): 用于读取用户在终端输入的回复消息。
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
// process 函数负责处理单个客户端连接的读写交互
type process struct{}
func (p *process) Run(conn net.Conn) {
defer conn.Close() // 确保连接在函数退出时关闭
var tmp [128]byte
reader := bufio.NewReader(os.Stdin) // 创建标准输入读取器
for {
// 1. 从网络连接读取客户端发来的数据
n, err := conn.Read(tmp[:])
if err != nil {
fmt.Printf("read from connection failed, err:%v\n", err)
break
}
// 打印收到的客户端消息
fmt.Println("Client:", string(tmp[:n]))
// 2. 提示用户输入服务端回复
fmt.Print("Server:")
text, _ := reader.ReadString('\n')
msg := strings.TrimSpace(text) // 去除首尾空格及换行符
// 3. 将用户输入的消息写回连接
_, err = conn.Write([]byte(msg))
if err != nil {
fmt.Printf("write to connection failed, err:%v\n", err)
break
}
}
}
func main() {
// 监听 TCP 端口,此处设置为本地 10086
listen, err := net.Listen("tcp", "127.0.0.1:10086")
if err != nil {
fmt.Printf("start server failed, err:%v\n", err)
return
}
defer listen.Close() // 建议关闭监听器
fmt.Println("Server listening on 127.0.0.1:10086...")
// 4. 循环接受新连接
for {
conn, err := listen.Accept()
if err != nil {
fmt.Printf("accept failed, err:%v\n", err)
continue
}
// 5. 为每个新连接启动一个 goroutine 进行处理
go func(c net.Conn) {
p := &process{}
p.Run(c)
}(conn)
}
}
第2步:客户端代码实现 (client.go)
目的: 连接到服务端,并在循环中实现用户输入发送与服务端响应接收。
关键逻辑:
- net.Dial: 建立与服务端的 TCP 连接。
- 循环检测输入,若输入 exit 则断开连接。
- 同时处理用户输入和网络读取,保持交互流畅。
package main
import (
"bufio"
"fmt"
"net"
"os"
"strings"
)
func main() {
// 1. 建立与服务端的 TCP 连接
conn, err := net.Dial("tcp", "127.0.0.1:10086")
if err != nil {
fmt.Printf("connection failed, err:%v", err)
return
}
defer conn.Close() // 确保退出前关闭连接
var msg string
var tmp [128]byte
reader := bufio.NewReader(os.Stdin) // 标准输入读取器
for {
// 2. 提示用户输入消息
fmt.Print("Client:")
text, _ := reader.ReadString('\n')
msg = strings.TrimSpace(text)
// 退出条件判断
if msg == "exit" {
break
}
// 3. 将消息写入网络连接发送给服务端
_, err := conn.Write([]byte(msg))
if err != nil {
fmt.Printf("write failed, err:%v", err)
return
}
// 4. 从网络连接读取服务端返回的数据
n, err := conn.Read(tmp[:])
if err != nil {
fmt.Printf("read from server failed, err:%v", err)
return
}
// 打印服务端回复
fmt.Println("Server:", string(tmp[:n]))
}
}
运行效果与测试
在实际运行中,建议先启动服务端程序,再打开另一个终端启动客户端程序。以下是典型的交互流程模拟:
D:\Software\godata\src\demo\server> go run server.go
Server listening on 127.0.0.1:10086...
Client: 你好
Server: hello
Client: 很高兴见到你
Server: 我也是
Client: exit
注意事项与排错
- 端口冲突: 如果运行时报错
bind: address already in use,说明 10086 端口已被占用,请修改代码中的端口号或关闭占用该端口的进程。 - 连接中断: 如果客户端非正常退出(如强制关闭窗口),服务端可能无法立即感知连接断开,导致后续
Read阻塞。在生产环境中通常需要心跳机制或超时设置来处理僵尸连接。 - 缓冲区大小: 示例中使用了
[128]byte作为缓冲区,适用于简短文本。若传输大文件,需调整缓冲区大小或使用分块传输。
以上就是 Go 语言实现基于 TCP 的简易聊天小工具的详细内容,更多关于 Go 语言网络编程的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









