net.listen后必须写accept循环,否则telnet连不上;需用for循环持续调用listener.accept(),每个连接启动goroutine处理,并设置读写deadline、正确关闭conn。

net.Listen 后必须写 Accept 循环,否则 telnet 连不上
很多人跑通 net.Listen 就以为服务起来了,结果 telnet 127.0.0.1 8080 直接超时或报 “Connection refused”——根本原因是没调用 Accept。
net.Listen 只是打开端口、返回一个 net.Listener,它不自动接收连接。
必须显式写 for 循环持续调用 listener.Accept(),否则只处理第一个连接就退出,后续所有连接都被丢弃。
-
net.Listen("tcp", ":8080")的地址格式不能省略tcp:前缀,否则 panic:listen tcp: address :8080: missing protocol scheme - 端口被占用时错误是:
listen tcp :8080: bind: address already in use,先用lsof -i :8080杀掉旧进程 -
Accept()是阻塞调用,出错(如文件描述符耗尽)时返回非 nilerr,不能忽略,应log.Println(err)后continue
每个 conn 必须起 goroutine 处理,否则新连接被卡住
如果在 for 循环里直接 handleConn(conn) 同步执行,那么第二个客户端连上来时,Accept() 会一直阻塞,直到第一个连接的 handleConn 返回——相当于单线程排队服务,完全浪费 Go 并发能力。
- 正确做法是:
go handleConn(conn),让每个连接在独立 goroutine 中运行 - goroutine 内部要确保
conn.Close()被调用,建议用defer conn.Close() - 别在 goroutine 里 close 之后还继续
Read,否则会返回io.EOF或use of closed network connection
conn.Read/Write 必须设 deadline,且不能假设一次读完
TCP 是字节流,没有消息边界。conn.Read(buf) 可能只读到部分数据(比如发了 100 字节,第一次只返回 32 字节),也可能因客户端断连返回 io.EOF;Write 同样可能只写出部分字节。不加控制,goroutine 会永久阻塞在 Read 上。
在 Golang 中使用 samber/hot 进行内存缓存,支持 LRU、LFU、TinyLFU、W‑TinyLFU、S3FIFO、ARC、TwoQueue、SIEVE、FIFO 等淘汰算法,提供 TTL、缓存加载器及分片功能。
- 务必在
conn上设置读写超时:conn.SetReadDeadline(time.Now().Add(5 * time.Second)) - 不要依赖单次
Read拿到完整业务包;常见方案是加长度头(如前 4 字节 int32 表示 payload 长度),先读够头再读正文 -
Write只把数据拷进内核 buffer,不代表对方已收到;要确认送达,得靠上层 ACK 或应用层应答
UDP 用 ListenUDP,别和 DialUDP 混用
net.ListenUDP 和 net.DialUDP 返回的都是 *net.UDPConn,但语义完全不同:前者是服务端入口,后者是客户端发包工具。混用会导致逻辑错乱甚至 panic。
- 服务端必须用
net.ListenUDP("udp", &net.UDPAddr{Port: 9999}),然后循环调用ReadFromUDP(buf)接收任意来源的数据 - 客户端若只需单向上报(如日志),用
net.DialUDP("udp", nil, &net.UDPAddr{IP: ..., Port: 9999})更方便,返回的 conn 自带目标地址,Write()不用每次传UDPAddr - UDP 没有连接状态,
DialUDP不会真正建连,也不会报 “connection refused”;目标端口无人监听时,发包不报错但对方收不到 - UDP 包大小受 MTU 限制(通常 ≤1500 字节),接收缓冲区不够大会截断,
make([]byte, 65536)更安全
实际跑起来时,最容易被跳过的不是语法,而是超时设置和 Accept 循环——这两个点漏掉,程序看起来“能编译”,但根本没法通信。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










