刚开始接触网络编程那阵子,我最常干的事就是一边翻 man 手册,一边对着师兄留下的代码抄。后来真开始自己写服务端、调协议栈的时候才发现,光知道函数签名远远不够,真正值钱的是“这个函数在什么场景下为什么这么用”。这份网络编程核心函数速查,就是我从实际项目里一点点攒出来的,重点不是罗列参数,而是把 socket 生命周期里那些最容易踩坑的经典用法讲清楚,适合正在学 Linux 网络编程、C/C++ 后端的同学,也适合写了好几年业务代码但没系统捋过 socket 底层细节的朋友。
1. 为什么要有一份“网络编程核心函数速查”
1.1 这份速查表解决什么问题
网络编程的函数体系其实非常稳定,从 BSD socket 诞生到现在,核心接口基本没变过。但稳定不等于简单,真正让人头疼的是这些函数的语义藏在细节里:比如 send() 返回了多少字节到底代表什么,listen() 的 backlog 参数在不同内核版本里行为完全不一样,accept() 返回的 fd 和监听 fd 又有哪些天壤之别。这些知识点散落在 man 手册、内核源码和各种博客里,新手想一次性吃透,难度相当大。
我见过不少同事,写 TCP 客户端代码的时候一上来就调 connect(),完全不考虑非阻塞场景下它会返回 EINPROGRESS;写 UDP 的时候拿 send() 去发数据,结果发现报文发是发出去了,但和 sendto() 的语义完全不同。这些问题不是代码写不出来,而是对函数背后的设计逻辑缺少整体认知。所以这份速查不是把函数签名抄一遍,而是把所有经典用法按“套接字生命周期-数据收发-地址解析-事件驱动”这条主线串起来,让你在写具体代码前,脑子里先有一张完整的调用地图。
1.2 速查怎么用才能变成真正的能力
拿到这份速查,千万别把它当成字典从头读到尾。我的建议是:先看第 2 章,把套接字从创建到关闭的完整链路捋顺,这一章是整个网络编程的骨架;然后带着自己平时写代码时遇到的问题去查第 3 章和第 4 章,这两章解决的是“数据怎么发”“地址怎么写”的实操问题;最后再看第 5 章的 IO 多路复用,因为真正的高并发服务端几乎离不开 epoll,但没搞清楚前几章,直接上 epoll 只会让你在回调地狱里越陷越深。
我的个人习惯是,每学一个函数,就在草稿纸上画一遍它的状态转换,然后对照这这份速查里的“注意事项”看一遍自己有没有漏掉边界情况。比如 accept() 返回 EMFILE 怎么办、send() 碰到 SIGPIPE 怎么处理,这些在普通文档里很少被强调,但恰恰是线上事故的高发源头。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 套接字生命周期函数:从创建到关闭的完整链路
2.1 socket():三参数背后的现代Linux扩展
int socket(int domain, int type, int protocol) 是网络编程的起点。domain 决定协议族,AF_INET 是 IPv4,AF_INET6 是 IPv6,AF_UNIX 是本地域套接字;type 决定通信语义,SOCK_STREAM 代表可靠的字节流(TCP),SOCK_DGRAM 代表不可靠的数据报(UDP);protocol 通常填 0,表示由内核根据前两个参数自动选择默认协议。
这里有个细节很多人没注意到:在 Linux 上,type 参数可以叠加额外标志位,比如 SOCK_NONBLOCK 和 SOCK_CLOEXEC。它的作用是在创建套接字的同时就设置好非阻塞属性和执行 exec 时自动关闭,省去了后续再调 fcntl() 的麻烦。如果你在写高性能服务,这两个标志位几乎是必选的,因为它们能有效避免多线程环境下 fcntl() 和 exec() 之间的竞态窗口。早期代码里常见的 socket(AF_INET, SOCK_STREAM, 0) 后跟 fcntl(fd, F_SETFL, O_NONBLOCK) 的写法,在新代码里其实可以一行合并。
2.2 bind()与listen():服务端地址绑定与监听队列的细节
bind() 的作用是把套接字和本地的 IP 地址、端口绑定在一起。服务端必须调用 bind(),否则内核会随机
