本文最后更新于 2025-10-30,文章内容可能已经过时。

在Golang中,使用标准库net包可以非常方便地实现TCP服务器与客户端之间的通信。下面详细介绍如何实现一个简单的TCP服务器与客户端互发消息的程序。

一、TCP服务器实现

服务器的主要功能是监听指定端口,接受客户端连接,并处理数据收发。

package main

import (
	"fmt"
	"log"
	"net"
)

// 处理单个客户端连接
func handleConnection(conn net.Conn) {
	defer conn.Close()
	
	// 创建缓冲区
	buffer := make([]byte, 1024)
	
	// 循环读取客户端发送的数据
	for {
		n, err := conn.Read(buffer)
		if err != nil {
			// 连接断开或出错时退出
			fmt.Printf("客户端 %s 断开连接: %v\n", conn.RemoteAddr(), err)
			return
		}
		
		// 将接收到的数据打印出来
		received := string(buffer[:n])
		fmt.Printf("收到客户端消息: %s", received)
		
		// 向客户端发送响应
		response := "服务器已收到: " + received
		conn.Write([]byte(response))
	}
}

func main() {
	// 监听TCP端口
	listener, err := net.Listen("tcp", "127.0.0.1:8080")
	if err != nil {
		log.Fatal("监听失败:", err)
	}
	defer listener.Close()
	
	fmt.Println("服务器启动,监听 8080 端口...")
	
	// 循环等待客户端连接
	for {
		conn, err := listener.Accept()
		if err != nil {
			log.Println("接受连接出错:", err)
			continue
		}
		
		// 为每个连接启动一个goroutine处理
		go handleConnection(conn)
	}
}

二、TCP客户端实现

客户端负责主动连接服务器,发送消息并接收服务器响应。

package main

import (
	"bufio"
	"fmt"
	"log"
	"net"
	"os"
	"strings"
)

func main() {
	// 连接到服务器
	conn, err := net.Dial("tcp", "127.0.0.1:8080")
	if err != nil {
		log.Fatal("连接失败:", err)
	}
	defer conn.Close()
	
	fmt.Println("已连接到服务器,开始发送消息...")
	
	// 创建标准输入读取器
	reader := bufio.NewReader(os.Stdin)
	
	// 循环发送消息
	for {
		// 从终端读取用户输入
		fmt.Print("你: ")
		input, err := reader.ReadString('\n')
		if err != nil {
			fmt.Println("读取输入失败:", err)
			break
		}
		
		// 如果输入"exit"则退出
		if strings.TrimSpace(input) == "exit" {
			fmt.Println("客户端退出...")
			break
		}
		
		// 发送消息到服务器
		_, err = conn.Write([]byte(input))
		if err != nil {
			fmt.Println("发送消息失败:", err)
			break
		}
		
		// 读取服务器响应
		buffer := make([]byte, 1024)
		n, err := conn.Read(buffer)
		if err != nil {
			fmt.Println("接收响应失败:", err)
			break
		}
		
		// 显示服务器响应
		fmt.Printf("服务器: %s", string(buffer[:n]))
	}
}

三、运行流程

  1. 先启动服务器

    go run server.go
    

    服务器将启动并监听8080端口

  2. 再启动客户端

    go run client.go
    

    客户端将连接到服务器,并开始发送和接收消息

  3. 交互示例

    服务器启动,监听 8080 端口...
    已连接到服务器,开始发送消息...
    你: 你好
    服务器: 服务器已收到: 你好
    你: 今天天气怎么样?
    服务器: 服务器已收到: 今天天气怎么样?
    你: exit
    客户端退出...
    

四、关键点说明

  1. 连接管理

    • 服务器使用net.Listen监听端口
    • 服务器使用listener.Accept()接受连接
    • 每个连接使用goroutine处理,实现并发
  2. 数据收发

    • 服务器使用conn.Read()读取数据
    • 服务器使用conn.Write()发送数据
    • 客户端同样使用conn.Write()发送和conn.Read()接收
  3. 粘包处理

    • TCP是流式协议,不保证消息边界
    • 本示例中使用换行符\n作为消息结束标记
    • 实际应用中可考虑添加消息长度前缀或使用自描述格式
  4. 错误处理

    • 所有网络操作都需检查错误
    • 连接断开时及时清理资源

五、注意事项

  1. 并发安全:如果需要维护多个连接的列表,需考虑并发安全(如使用互斥锁或channel)

  2. 资源管理

    • 服务器端使用defer conn.Close()确保连接关闭
    • 客户端同样需要正确关闭连接
  3. 生产环境增强

    • 添加超时控制
    • 添加错误重试机制
    • 考虑连接池管理(避免短连接过多)
  4. 端口占用:确保8080端口未被其他程序占用

六、扩展建议

  1. 实现广播功能

    • 服务器维护一个连接列表
    • 收到消息后广播给所有连接
  2. 添加用户标识

    • 在消息中包含发送者标识
    • 便于区分不同客户端
  3. 使用更高效的数据格式

    • 如JSON、Protobuf等自描述格式
    • 避免粘包问题
  4. 添加心跳机制

    • 定期检查客户端是否存活
    • 及时清理失效连接

以上就是一个完整的Golang TCP服务器与客户端互发消息的实现方案。通过这个示例,可以快速理解Golang网络编程的基本原理和实现方式,为进一步开发更复杂的网络应用打下基础。