C++怎么使用Socket_C++网络编程教程【通信】

4次阅读

socket()返回-1不一定失败,需查errno或wsagetlasterror();bind()端口占用可设so_reuseaddr;recv()返回0仅tcp表示对端关闭;select()会破坏fd_set,须每次重置。

C++怎么使用Socket_C++网络编程教程【通信】

socket() 函数返回 -1 是不是一定失败了?

不一定。c++ 里调用 socket() 返回 -1 只代表系统调用失败,但真正原因得看 errno——比如 EAFNOSUPPORT(地址族不支持)、EMFILE(进程打开文件数超限)或 ENFILE(系统级文件描述符耗尽)。别一看到 -1 就以为是代码写错了。

  • 务必在 socket() 后立即检查 errno,而不是靠打印“创建失败”糊弄过去
  • linux 下可用 strerror(errno) 获取可读提示;windowsWSAGetLastError(),且必须先调 WSAStartup()
  • 常见误操作:在未初始化 Winsock 的 Windows 程序里直接调 socket(),此时返回 -1,errno 无意义,得查 WSAGetLastError() 返回 WSANOTINITIALISED

bind() 失败报 “Address already in use” 怎么办?

这是端口被占用的典型提示,但不一定是别的程序占着——更可能是你上次运行的程序没正确关闭 socket,TIME_WAIT 状态还在占着端口。直接改端口号只是绕开问题,不是解决。

  • 服务端启动前,设置 SO_REUSEADDR 选项能重用处于 TIME_WAIT 的本地地址:setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))
  • SO_REUSEPORT(Linux 3.9+、macos)可允许多个 socket 绑定同一地址+端口,但需谨慎:它会把连接随机分发到多个监听者,不是所有场景都适用
  • 注意:Windows 默认不支持 SO_REUSEPORT,且 SO_REUSEADDR 在 Windows 上行为略有不同(比如允许跨协议重用),别盲目照搬 Linux 示例

recv() 返回 0 是不是网络断开了?

是,但只对 TCP 成立。这个返回值表示对端已调用 shutdown(SHUT_WR) 或正常 close(),TCP 连接进入 FIN_WAIT 状态,本端读缓冲区数据已空。udprecv() 永远不会返回 0。

  • TCP 场景下,recv() 返回 0 应立即关闭本端 socket,否则可能造成资源泄漏或后续 send() 触发 SIGPIPE
  • 别用 recv() 返回值是否为 0 来判断 UDP 是否“断连”——UDP 本就不维护连接,丢包、目标不可达都只会让 recv() 阻塞或超时,不会返回 0
  • 如果想探测 TCP 对端是否存活,得用 SO_KEEPALIVE 选项,或者自己实现应用层心跳;依赖 recv() 返回 0 只能捕获“优雅关闭”,抓不到崩溃掉线

select() 调用后 fd_set 里的 socket 全没了?

对,select() 是**破坏性调用**:每次返回后,fd_set 会被内核修改,只保留就绪的 socket。如果你没在每次循环开始前重新 FD_SET() 所有要监听的 socket,就会漏掉未就绪的那些。

立即学习C++免费学习笔记(深入)”;

  • 标准写法是:每次进入 select() 前,用原始备份的 fd_set(比如 all_fds)重新赋值给待检测的 readfds
  • 别把 fd_set 当成状态缓存——它只是临时传给内核的“问题列表”,不是“结果列表”
  • 注意 select() 的最大文件描述符限制(通常是 1024),超出会导致静默失败;现代项目建议直接用 epoll(Linux)或 kqueue(macOS/BSD),它们不修改输入结构体,也无硬上限

实际写 C++ 网络代码时,最常被忽略的是错误检查粒度和平台差异:同一个 errno 值在 Linux 和 macOS 上含义可能不同,Windows 完全另起一套错误码体系。别指望一份错误处理逻辑跑遍所有平台。

text=ZqhQzanResources