Go语言基于TCP实现简易聊天工具的示例代码

顾言
顾言
发布时间:2026-10-15 | 2人浏览过
原创

本文演示如何使用 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 语言网络编程的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表