端口被占或权限不足时应查杀占用进程或改用高位端口;客户端断开需正确处理io.EOF并显式关闭连接;广播消息须用线程安全结构与写goroutine隔离;服务器连不上需检查防火墙、安全组及监听地址是否为0.0.0.0。

Go 的 net.Listen 启动 TCP 服务时,端口被占或权限不足怎么办
直接监听失败是新手第一道坎,错误通常是 listen tcp :8080: bind: address already in use 或 permission denied。前者说明端口正被其他进程占用,后者常见于 Linux/macOS 尝试绑定 1024 以下端口(如 :80)却没加 sudo。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 查端口:用
lsof -i :8080(macOS/Linux)或netstat -ano | findstr :8080(Windows)找 PID,再kill -9 PID - 换端口比提权更安全:开发阶段一律用
:8080、:9000这类高位端口,避免依赖 root 权限 - 监听地址别写死
"localhost:8080"——它只接受本机连接;对外提供服务必须用":8080"(即"0.0.0.0:8080")
goroutine 处理每个连接时,为什么客户端一断开就 panic
典型现象是读取 conn.Read 返回 io.EOF 后继续操作,或在已关闭的 conn.Write 上写入,触发 write: broken pipe。根本原因是没区分正常 EOF 和真实错误,也没做连接生命周期管理。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
-
conn.Read返回n == 0 && err == io.EOF是标准断开信号,应立即break当前 goroutine - 写操作前务必检查
conn.SetWriteDeadline,否则慢客户端或网络抖动会导致 goroutine 卡死堆积 - 不要在 goroutine 里直接
defer conn.Close()——它会等整个函数退出才关,而读写可能异步进行;应在明确断开逻辑处显式关
多个客户端并发发消息,怎么让所有人实时收到而不丢不乱
裸用 map[net.Conn]struct{} 存连接 + 每次广播遍历写,看似简单,实际会因并发写同一连接、无缓冲 channel 阻塞、或 map 非线程安全导致崩溃或消息丢失。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 用
sync.RWMutex保护连接集合读写,或改用sync.Map(注意它不支持遍历,需额外维护 slice) - 给每个连接配独立的写 goroutine + 带缓冲 channel(如
chan string缓冲 64),把广播拆成“发消息到 channel”和“从 channel 取出写 conn”两步 - 广播时不等所有写完成:启动写 goroutine 后立即返回,避免阻塞主线程;失败写入可在 goroutine 内单独处理(如记录日志、清理连接)
为什么本地测试通,一上服务器就收不到消息或连不上
最常被忽略的是防火墙和 NAT。云服务器(如阿里云、AWS)默认关闭所有入向端口,即使 Go 程序监听成功,外部请求也进不来;本地路由器也可能拦截非 80/443 端口。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 先 telnet 测试连通性:
telnet your-server-ip 8080,不通就不是代码问题 - 云平台必须在安全组里放行对应端口(TCP 协议,源 IP 可设为
0.0.0.0/0临时调试) - 确认程序监听的是
":8080"而非"127.0.0.1:8080",后者在服务器上只能本机访问 - 如果用内网穿透或反向代理(如 nginx),确保 proxy_pass 指向正确地址,且启用了 WebSocket 升级头(若后续扩展用 ws)
真正的难点不在 goroutine 数量或 channel 大小,而在于连接状态判断是否精准、资源释放是否及时、以及网络边界条件是否被覆盖——这些地方一漏,服务上线后就是半夜告警。


















