TCP服务器
listener, err := net.Listen("tcp", ":8080")监听端口号conn, err := listener.Accept()客户端有数据buf := make([]byte, 1024)定义缓冲区保存数据n, err := conn.Read(buf)读取数据_, err = conn.Write(sendMsg)写数据
服务端代码
go
package main
// 导入必要的包
import (
"fmt" // 用于打印日志
"net" // 网络编程核心包,所有TCP/UDP相关功能都在这里
)
// main 函数:程序入口
func main() {
// ===================== 1. 启动监听 =====================
// net.Listen:Go 最基础、最简单的监听方法
// 第一个参数 "tcp":表示使用 TCP 协议
// 第二个参数 ":8080":监听地址
//
// 地址格式分 3 种:
// 1. ":8080" → 不写IP,监听本机【所有网卡】的 8080 端口(最常用)
// 2. "127.0.0.1:8080" → 只允许【本机自己】访问,外部设备连不上(安全私有)
// 3. "192.168.1.100:8080" → 只监听【某一个具体网卡】,其他网卡连不上
//
// 返回值类型:
// listener:net.Listener 接口类型,代表TCP服务监听器
// err:error 类型,如果启动失败(端口被占用、权限不足)会返回错误
listener, err := net.Listen("tcp", ":8080")
// 如果启动失败,打印错误并退出
if err != nil {
fmt.Println("服务启动失败:", err)
return
}
// defer:程序退出前,自动关闭监听器,释放端口
// 类型:net.Listener
defer listener.Close()
fmt.Println("✅ TCP 服务已启动,监听 :8080 端口")
// ===================== 2. 无限循环接收连接 =====================
// 死循环:持续等待并接收客户端连接
for {
// Accept():阻塞等待客户端连接
// 没有客户端连接时,程序会停在这里不动
//
// 返回值类型:
// conn:net.Conn 接口类型,代表一个客户端连接通道
// err:error 类型,接收失败时返回
conn, err := listener.Accept()
if err != nil {
fmt.Println("接收客户端连接失败:", err)
continue
}
// ===================== 获取客户端&服务器所有网络信息 =====================
// RemoteAddr():返回客户端的地址信息
// 返回类型:net.Addr
clientAddr := conn.RemoteAddr()
// LocalAddr():返回服务器本地地址(本机IP + 端口)
// 返回类型:net.Addr
serverAddr := conn.LocalAddr()
// 类型断言:将 net.Addr 转为具体的 *net.TCPAddr,才能单独获取 IP 和端口
clientTCPAddr, _ := clientAddr.(*net.TCPAddr)
serverTCPAddr, _ := serverAddr.(*net.TCPAddr)
// 打印完整连接信息
fmt.Println("==================================")
fmt.Println("🎉 新客户端连接")
fmt.Println("客户端完整地址 :", clientAddr) // 客户端 IP+端口
fmt.Println("客户端 IP :", clientTCPAddr.IP) // 纯客户端 IP
fmt.Println("客户端 端口 :", clientTCPAddr.Port) // 纯客户端端口
fmt.Println("客户端协议类型 :", clientTCPAddr.Network()) // tcp/tcp4
fmt.Println("==================================")
fmt.Println("服务器本地地址 :", serverAddr) // 服务器 IP+端口
fmt.Println("服务器 IP :", serverTCPAddr.IP)
fmt.Println("服务器 端口 :", serverTCPAddr.Port)
fmt.Println("==================================")
// ===================== 启动协程处理连接 =====================
// 必须用 go 关键字启动协程!
// 如果不启动协程,同一时间只能处理一个客户端
// 启动协程后,主循环可以继续接收新连接
go handleClient(conn)
}
}
// ===================== 处理单个客户端连接 =====================
// handleClient
// 参数类型:
// conn:net.Conn 接口类型,代表与客户端的TCP连接通道
func handleClient(conn net.Conn) {
// defer:函数退出时,自动关闭客户端连接
// 作用:防止连接泄漏,必须写!
defer conn.Close()
// 定义缓冲区
// 类型:[]byte(字节切片),长度 1024 字节
buf := make([]byte, 1024)
// 循环读取客户端数据
for {
// Read:从客户端读取数据到缓冲区
// 参数:[]byte 类型
// 返回值:
// n:int 类型,实际读到的字节数
// err:error 类型,读取失败(断开/超时)返回
n, err := conn.Read(buf)
if err != nil {
fmt.Println("客户端断开连接:", conn.RemoteAddr(), "错误:", err)
return
}
// 打印收到的数据
fmt.Printf("📥 收到客户端数据:%s\n", string(buf[:n]))
// Write:把数据写回客户端(echo 回显服务:收到什么返回什么)
// 参数:[]byte 类型
// 返回值:写入字节数 + 错误
_, _ = conn.Write(buf[:n])
}
}
客户端代码
go
package main
import (
"fmt"
"net"
"time"
)
// 客户端入口
func main() {
// ===================== 1. 连接 TCP 服务器 =====================
// net.Dial:Go 客户端最基础的「建立连接」方法
// 第一个参数 "tcp":使用 TCP 协议
// 第二个参数 "127.0.0.1:8080":要连接的【服务器IP + 端口】
//
// 返回值类型:
// conn:net.Conn 接口类型,代表与服务器的连接通道
// err:error 类型,连接失败返回错误
conn, err := net.Dial("tcp", "192.168.139.177:8080")
if err != nil {
fmt.Println("❌ 连接服务器失败:", err)
return
}
// 函数退出时关闭连接,防止资源泄漏
defer conn.Close()
fmt.Println("✅ 成功连接到服务器:", conn.RemoteAddr())
// ===================== 2. 发送数据给服务器 =====================
// 准备要发送的数据
// 类型:[]byte(字节切片)
sendMsg := []byte("Hello TCP Server!")
// 发送数据
// Write:把数据写到服务器
// 返回值 n:成功发送的字节数
_, err = conn.Write(sendMsg)
if err != nil {
fmt.Println("发送失败:", err)
return
}
fmt.Println("📤 已发送数据:", string(sendMsg))
// ===================== 3. 接收服务器回显的数据 =====================
// 缓冲区:存储服务器返回的数据
// 类型:[]byte,长度 1024
buf := make([]byte, 1024)
// 设置读取超时,防止一直卡住等不到数据
_ = conn.SetReadDeadline(time.Now().Add(3 * time.Second))
// 读取服务器返回的数据
// n:实际读到的字节长度
n, err := conn.Read(buf)
if err != nil {
fmt.Println("接收失败:", err)
return
}
fmt.Println("📥 收到服务器回显:", string(buf[:n]))
fmt.Println("🎉 客户端运行完成!")
}