Go网络编程面试重在实践能力,核心是正确处理连接生命周期、超时控制与资源清理:需检查listen错误、defer关闭监听器、goroutine并发Accept;HTTP超时须分层设置ReadHeaderTimeout/IdleTimeout及handler内context.WithTimeout;长连接需协议帧+优雅关闭;优先使用net/http而非raw net.Conn以避免重复造轮子。

Go 网络编程面试不考背概念,考的是你能不能在 net.Conn、net/http、net.Listen 这些基础接口上快速写出可运行、可调试、不泄露资源的代码。真正卡人的点从来不是“会不会 listen”,而是“连接断了怎么 cleanup”“超时怎么设才不误杀”“为什么用 bufio.Reader 而不用直接 Read”。
如何正确启动一个 TCP 服务并避免常见 panic
很多人写 net.Listen("tcp", ":8080") 就停了,但实际部署中必须处理错误、关闭监听器、防止 goroutine 泄漏:
- 永远检查
err != nil—— 比如端口被占时返回listen tcp :8080: bind: address already in use,不判断会 panic - 监听器要显式
defer ln.Close(),否则进程退出前 socket 可能没释放 -
Accept()必须在 goroutine 中循环调用,否则只处理一个连接就阻塞退出;但每个连接也必须起新 goroutine,否则串行处理无法并发 - 别用
for {}死循环等连接,要用for { conn, err := ln.Accept(); if err != nil { break } go handle(conn) },让Accept错误(如监听器被关)能自然退出
HTTP Server 中 context.WithTimeout 为什么不能只包 handler
只对 http.HandleFunc 内部逻辑加 context.WithTimeout 是无效的 —— 它拦不住连接建立、TLS 握手、请求头读取这些前置阶段。真正的超时控制必须下沉到连接层:
-
http.Server的ReadTimeout/WriteTimeout已被标记为 deprecated,官方推荐用ReadHeaderTimeout+IdleTimeout -
ReadHeaderTimeout控制从连接建立到读完 request header 的最大时间(防慢速攻击) -
IdleTimeout控制两次请求之间的空闲时间(HTTP/1.1 keep-alive 场景) - 如果要做 per-request 超时(比如业务逻辑最多跑 5s),必须在 handler 内部用
ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second),且后续所有 I/O(DB 查询、下游 HTTP 调用)都要传这个 ctx
长连接场景下如何安全关闭连接并通知对方
所谓“长连接”,本质是复用 net.Conn 多次收发数据。但没人告诉你:主动关闭方进入 TIME_WAIT,被动方可能还在发数据 —— 这时直接 conn.Close() 会导致对方 read 返回 io.EOF 或 broken pipe,但业务层未必能区分是正常结束还是网络异常:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
立即学习“go语言免费学习笔记(深入)”;
- 应用层需定义协议帧(如带 length header 的二进制包,或换行分隔的文本),而非依赖 TCP 流式语义
- 优雅关闭流程:先发送自定义 “bye” 帧 → 等对方回 “ack” → 再
conn.Close();若超时未收到 ack,强制 close - 接收方读到 EOF 后,必须检查是否已收到完整协议帧(比如缓冲区还有半包),不能直接退出
- 用
conn.SetReadDeadline替代无期限阻塞读,避免 goroutine 卡死
为什么用 net/http 而不是 raw net.Conn 写 API 服务
除非你在写代理、协议转换网关或性能压榨到极致的场景,否则不要绕过 net/http。它的默认行为已经覆盖了绝大多数边界情况:
-
http.Server自动处理 HTTP/1.1 pipelining、chunked encoding、header 解析、content-length 校验 - 它内置连接池管理(client 端)和 keep-alive 生命周期(server 端),而 raw
net.Conn需自己实现心跳、空闲检测、重连逻辑 -
http.Request.Body是封装好的io.ReadCloser,自动处理 body 截断、max memory limit(通过MaxBytesReader)、gzip 解压 - 最实际的一点:Prometheus metrics、pprof、trace 注入都基于
http.Handler接口,自己造轮子等于放弃可观测性基建
真正容易被忽略的,是连接生命周期和上下文传递的耦合 —— 一个 http.Request 的 Context 在连接断开时自动 cancel,但如果你在 handler 里启了 goroutine 去异步处理,又没把 ctx 传进去,那个 goroutine 就会永远挂着,变成 goroutine leak。


















