GO_网络编程---Socket TCP 套接字

发布时间:2026/7/24 2:52:57

GO_网络编程---Socket TCP 套接字 一、套接字 (Socket) 基础概念1. Socket 核心理解Socket 可以看作进程间通信的管道两端分别是客户端、服务端中间依托网络传输类比管道管道用于本机进程通信Socket 用于跨主机网络通信。Socket 分为读、写两种操作一套 Socket 连接同时具备读写能力读写分离 / 双向通信。Channel 是 Go 语言内部协程通信管道Socket 是网络通信管道二者作用场景不同。2. TCP 与 UDP 区别表格协议特性适用场景本教程选用TCP面向连接、可靠传输、有三次握手、数据无丢失不乱序文件传输、聊天、接口通信、需要稳定数据全程使用 TCPUDP无连接、不可靠、无握手、速度快直播、语音通话、游戏实时帧本文不涉及3. 网络架构模型1C/S 客户端 / 服务端模型TCP 通信核心模型Client 客户端主动发起连接、主动发送请求手机 APP、自定义客户端程序Server 服务端被动监听端口、等待客户端连接、处理请求并返回响应通信流程客户端发起连接 → 三次握手建立 TCP 连接 → 客户端发数据 → 服务端处理 → 服务端回传数据 → 断开连接2B/S 浏览器 / 服务端模型本质是特殊的 C/S 架构浏览器 (Browser) 充当客户端后端服务为 Server基于 HTTP 协议底层依旧是 TCP Socket。4. TCP 连接建立三次握手客户端使用net.Dial()主动拨号连接服务端通过net.Listen()Accept()阻塞等待连接底层自动完成 TCP 三次握手开发者无需手动处理。二、前置测试工具netcat (nc)作用快速模拟 TCP 客户端测试服务端端口是否正常收发数据下载 nc 工具配置系统环境变量终端测试命令bashnc 127.0.0.1 8000连接本机 8000 端口 TCP 服务可手动输入数据发送给服务端并接收服务端返回内容。三、单客户端 TCP 服务端基础版功能说明仅支持单个客户端连接建立连接后读取客户端发送数据并打印连接结束自动关闭。完整可运行代码修正原代码语法错误gopackage main import ( fmt net ) func main() { // 1. 监听tcp端口 格式协议, ip:端口 listener, err : net.Listen(tcp, 127.0.0.1:8000) if err ! nil { fmt.Println(监听失败 err , err) return } defer listener.Close() // 程序退出关闭监听器 fmt.Println(服务端启动成功监听8000端口...) // 2. 阻塞等待客户端连接有客户端接入才会向下执行 conn, err : listener.Accept() if err ! nil { fmt.Println(接收连接失败 err , err) return } defer conn.Close() // 客户端连接结束关闭当前连接 fmt.Println(客户端已连接, conn.RemoteAddr()) // 3. 创建缓冲区读取客户端数据 buf : make([]byte, 1024) // 1024字节缓冲区 n, err1 : conn.Read(buf) if err1 ! nil { fmt.Println(读取数据失败 err1 , err1) return } // n实际读到的字节数只打印有效数据 fmt.Println(客户端发送数据, string(buf[:n])) }四、TCP 基础客户端单向发送数据功能说明主动连接指定 TCP 服务建立连接后发送一段字符串发送完成关闭连接。完整代码gopackage main import ( fmt net ) func main() { // 1. 主动拨号连接服务端 conn, err : net.Dial(tcp, 127.0.0.1:8000) if err ! nil { fmt.Println(连接服务端失败 err , err) return } defer conn.Close() // 程序退出释放连接 // 2. 向服务端写入数据 _, err conn.Write([]byte(are u ok)) if err ! nil { fmt.Println(发送数据失败, err) return } fmt.Println(数据发送完成) }五、并发 TCP 服务端支持多客户端协程处理需求同时接收多个客户端连接每个客户端单独开启 goroutine 协程处理互不阻塞循环读取客户端消息输入exit断开对应客户端连接将客户端发来的小写字母转大写回传给客户端完整修正代码修复原代码语法、变量、循环逻辑错误gopackage main import ( fmt net strings ) // 单独协程处理单个客户端连接 func HandleConn(conn net.Conn) { // 获取客户端地址 addr : conn.RemoteAddr().String() fmt.Printf([%s] 客户端连接成功\n, addr) defer conn.Close() // 客户端退出自动关闭连接 buf : make([]byte, 2048) for { // 循环读取客户端数据 n, err : conn.Read(buf) if err ! nil { fmt.Printf([%s] 读取失败/客户端断开 err %v\n, addr, err) return } // 截取有效数据去除换行符 data : string(buf[:n-1]) fmt.Printf([%s] 收到消息%s\n, addr, data) // 客户端发送exit断开连接 if data exit { fmt.Printf([%s] 客户端主动退出\n, addr) return } // 转大写回传给客户端 upperData : strings.ToUpper(data) _, err conn.Write([]byte(upperData \n)) if err ! nil { fmt.Printf([%s] 回写数据失败%v\n, addr, err) return } } } func main() { // 监听端口 listener, err : net.Listen(tcp, 127.0.0.1:8000) if err ! nil { fmt.Println(监听失败 err , err) return } defer listener.Close() fmt.Println(并发TCP服务启动监听8000端口...) // 无限循环接收客户端连接 for { conn, err : listener.Accept() if err ! nil { fmt.Println(接收连接异常 err , err) continue } // 每来一个客户端新建协程处理不阻塞主线程 go HandleConn(conn) } }测试方式多开多个终端执行nc 127.0.0.1 8000多个客户端可同时收发消息输入exit断开当前客户端。六、交互式 TCP 客户端可键盘输入发送 实时接收服务端返回需求一边读取键盘输入发送给服务端一边实时接收服务端返回的大写消息并打印读写使用两个协程分离互不阻塞完整修正代码修复原变量、括号、语法错误gopackage main import ( fmt net os ) func main() { // 连接服务端 conn, err : net.Dial(tcp, 127.0.0.1:8000) if err ! nil { fmt.Println(net.Dial 连接失败 err , err) return } defer conn.Close() fmt.Println(客户端连接服务端成功可输入消息发送exit退出) // 协程专门接收服务端返回的数据 go func() { buf : make([]byte, 1024) for { n, err : conn.Read(buf) if err ! nil { fmt.Println(读取服务端数据失败, err) return } // 打印服务端回传的大写内容 fmt.Printf(服务端返回%s\n, string(buf[:n-2])) } }() // 主线程读取键盘输入发送给服务端 inputBuf : make([]byte, 1024) for { // 读取控制台键盘输入 n, err : os.Stdin.Read(inputBuf) if err ! nil { fmt.Println(读取键盘输入失败 err , err) return } // 将键盘输入发送到服务端 _, err conn.Write(inputBuf[:n]) if err ! nil { fmt.Println(发送消息失败, err) return } } }七、核心 API 函数总结Go net 包 TCPnet.Listen(tcp, ip:port)服务端 API监听指定 TCP 端口返回监听器Listenerlistener.Accept()阻塞等待客户端连接连接成功返回通信句柄net.Connnet.Dial(tcp, ip:port)客户端 API主动拨号连接 TCP 服务直接得到net.Connconn.Read(buf []byte) (int, error)从连接中读取数据到缓冲区返回实际读取字节数conn.Write(buf []byte) (int, error)向连接写入字节数据发送给对端conn.RemoteAddr()获取对端客户端 / 服务端的 IP 端口地址defer conn.Close()延迟关闭 TCP 连接释放网络资源必须规范书写八、踩坑笔记缓冲区读取必须用buf[:n]不能直接打印完整 buf 切片未读到的字节是脏数据Read是阻塞 IO没有数据时程序会卡在 Read 处单线程服务端只能处理一个客户端多客户端必须搭配 goroutine 协程双向通信同时收发必须分协程处理读、写逻辑否则互相阻塞所有net.Conn、Listener使用完毕必须 Close否则端口占用、内存泄漏nc 测试时输入内容会自带换行符\n读取数据时需要截断换行再判断exit地址格式固定写法127.0.0.1:8000IP 和端口用冒号分隔不能多空格九、运行测试流程启动并发服务端程序终端输出监听成功方式 1新开终端使用nc 127.0.0.1 8000测试方式 2运行交互式客户端代码键盘输入文字服务端转大写返回输入exit客户端断开对应连接服务端继续接收其他新连接

相关新闻