网络编程的本质:协议之上的数据交换
网络编程不是“写网络”,而是让两个进程按约定格式收发字节。理解这一点,就能避开很多概念混淆:Socket 是操作系统提供的编程接口,TCP/IP 是底层协议栈,HTTP 是应用层协议。三者分层清晰,调试时才能定位问题出在哪一层。
Socket:从文件描述符说起
在类 Unix 系统中,Socket 本质上是一个文件描述符。socket() 创建端点,bind() 绑定地址端口,listen() 进入监听,accept() 取出连接,read/write 收发数据。服务端通常循环 accept,为每个连接分配处理逻辑。客户端则 connect() 后直接读写。理解这套调用顺序,是排查“连接被拒绝”“端口占用”等问题的基础。
TCP 与 UDP:选择取决于业务容忍度
TCP 提供有序、可靠、面向连接的字节流,代价是握手、确认与重传带来的延迟。UDP 无连接、不保证送达,但开销小、延迟低。文件传输、数据库连接选 TCP;实时音视频、游戏状态同步、DNS 查询常选 UDP。关键不是谁更“高级”,而是业务能否容忍丢包与乱序。
阻塞、非阻塞与 I/O 多路复用
阻塞 I/O 下,一个线程只能等一个连接,并发上来后线程数爆炸。非阻塞 I/O 配合轮询可减少等待,但空转消耗 CPU。I/O 多路复用(select/poll/epoll、kqueue)让单线程同时监视多个描述符,事件就绪再处理,是高并发服务器的常见底座。理解“就绪通知”与“实际读写”分离,是掌握事件驱动模型的关键。
HTTP:建立在 TCP 之上的应用协议
HTTP 请求由请求行、头部、空行、正文组成,响应结构类似。短连接每次重建 TCP,长连接复用减少握手开销。HTTP/1.1 的管道化受队头阻塞限制,HTTP/2 用多路复用缓解,HTTP/3 转向基于 UDP 的 QUIC。写 Web 服务时,框架封装了这些细节,但遇到超时、连接泄漏、头部过大等问题,仍需回到 TCP 层分析。
调试与学习路径建议
先用 telnet 或 nc 手工发一个 HTTP 请求,观察原始报文;再用抓包工具看三次握手与挥手;最后写一个最简单的 TCP echo 服务端与客户端。三步走完,网络编程的抽象概念会落地为可观察的行为。之后再深入 epoll 事件循环或 TLS 握手,就有了参照系。