socket()失败需查errno:Linux/macOS用perror或strerror,Windows用WSAGetLastError();常见错误包括EAFNOSUPPORT、EMFILE、ENFILE;Windows必先调WSAStartup()。

socket() 创建失败返回 -1 怎么查原因
直接看 errno,别只打个 “failed” 就完事。Linux/macOS 下用 perror("socket") 或 strerror(errno),Windows 用 WSAGetLastError() —— 两者不能混用,跨平台项目得加条件编译。
常见真实错误:EAFNOSUPPORT(地址族不支持,比如传了 AF_INET6 但系统没开 IPv6)、EMFILE(进程打开文件数超限)、ENFILE(系统级文件描述符耗尽)。Windows 还要记得先调 WSAStartup(),否则必返 -1,且 errno 无效。
- Linux/macOS:检查
ulimit -n,临时调高可用ulimit -n 4096 - Windows:必须在
socket()前调一次WSAStartup(MAKEWORD(2,2), &wsaData),且只调一次 - 不要忽略返回值:所有 socket API(
bind、connect、listen)都得判-1并查错
阻塞 connect() 卡住 30 秒以上怎么破
默认是阻塞的,DNS 解析慢、目标主机不响应、防火墙静默丢包,都会让 connect() 死等。生产环境必须设超时,但 C++ 标准库不提供直接接口,得靠底层控制。
Linux/macOS:先 socket() 创建后,用 fcntl(fd, F_SETFL, O_NONBLOCK) 设非阻塞,再 connect();若返回 -1 且 errno == EINPROGRESS,说明正在连,用 select() 或 poll() 等可写事件(就绪即连成或出错)。
立即学习“C++免费学习笔记(深入)”;
Windows:类似,用 ioctlsocket(sock, FIONBIO, &nonblocking),然后等 select() 的可写 + 异常集合。
- 别用
alarm()或信号中断connect()—— 不可移植,且信号处理易出竞态 -
setsockopt(..., SO_SNDTIMEO)对connect()无效,它只影响 send/recv - 超时建议设 5~10 秒,太短容不下正常网络抖动,太长拖垮用户体验
recv() 返回 0 是断连还是数据没了
返回 0 表示对端已调 close() 或 shutdown(SHUT_WR),TCP 连接进入半关闭状态 —— 这不是错误,是协议正常行为。你该清理资源,别当成“暂时没数据”继续轮询。
真正要警惕的是返回 -1:此时看 errno。常见 EAGAIN/EWOULDBLOCK(非阻塞模式下暂无数据),ECONNRESET(对方 RST 强制断连),ETIMEDOUT(中间设备超时切断)。
- 阻塞 socket 下
recv()返回 0 = 对端优雅关闭,该close()自己这端 - 非阻塞 socket 下,
recv()返回 -1 +errno == EAGAIN= 暂无数据,可稍后再试 - 别把
recv()返回值当字节数盲目拷贝到固定缓冲区 —— 必须用返回值做长度边界,否则内存越界
send() 不保证一次发完怎么办
TCP 是流式协议,send() 只承诺“尽力提交”,实际发出字节数可能小于请求长度(尤其大包或缓冲区满时)。返回值就是真实发出数,必须检查,不能假设全发出去了。
典型场景:想发 8KB,send() 只返回 1234,剩下 6789 字节得自己缓存、重试。重试前先确认 socket 是否仍可写(select() 等待可写事件),否则忙等浪费 CPU。
- 不要循环
send()直到全发完 —— 需配合select()或epoll_wait()避免空转 - 应用层需维护发送队列,把未发完的数据挂起,等 socket 可写再续发
- Windows 下注意
send()在阻塞模式可能发不完,而非阻塞模式下更常见部分发送
最麻烦的其实是粘包和拆包 —— send() 和 recv() 的边界不对应,协议设计时就得定长度头或分隔符,光靠 socket 层解决不了。










