非阻塞connect()返回-1且errno为EINPROGRESS属正常,需用select()等待可写事件后调用getsockopt()检查SO_ERROR获取真实结果;send()返回值小于请求长度是流控或缓冲区满所致,并非丢包;recv()返回0表示对端关闭连接,不可继续调用。

connect() 失败返回 -1 且 errno 是 EINPROGRESS 怎么办
非阻塞 TCP 客户端调用 connect() 后立刻返回 -1 并设 errno = EINPROGRESS,不是出错,是正常流程。Linux/Unix 下非阻塞 socket 的连接必须靠 select() 或 poll() 等待可写(write-ready)事件,再调用 getsockopt() 检查 SO_ERROR 获取真实连接结果。
- 直接对非阻塞 socket 调用
connect()后不检查就发数据 → 写失败,errno可能是EPIPE或ENOTCONN - 用
select()等待时,只监听读就漏掉连接完成信号 → 永远等不到,超时失败 -
getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &len)中&err必须是int*,传char或未初始化变量会导致判断失真
send() 返回值小于请求长度但没报错,是不是丢包了
不是丢包,是 TCP 流控或内核发送缓冲区满的正常表现。send() 只保证把数据拷入内核缓冲区,不保证已发出;返回值是实际拷入字节数,可能小于请求长度,也可能为 0(对端关闭连接)。
- 忽略返回值直接假设全发出去 → 后续数据覆盖、协议错乱
- 用
send(sockfd, buf, len, MSG_NOSIGNAL)但没处理部分发送 → 实际只发了前半截,对方收不到完整包 - 在循环里反复
send()却没用MSG_NOSIGNAL或屏蔽SIGPIPE→ 对端断连时进程被信号终止
recv() 返回 0 时能不能继续调用
不能。recv() 返回 0 表示对端已关闭连接(FIN),这是 TCP 协议定义的明确 EOF 信号。继续调用 recv() 仍会返回 0,send() 则会触发 Broken pipe 错误。
- 把
recv()返回 0 当作“暂时没数据”而继续轮询 → 浪费 CPU,且掩盖连接已终结的事实 - 收到 0 后还往 socket 写数据 → 下次
send()失败,errno通常是EPIPE或EINVAL - 没在返回 0 后 close(sockfd) → 文件描述符泄漏,连接状态滞留 TIME_WAIT
用 std::string 存接收缓冲区,为什么中文乱码或截断
std::string 不是二进制安全容器,但问题通常不出在它本身,而出在你用它的方式:std::string::c_str() 返回的指针不保证以 <p><code>std::string 不是二进制安全容器,但问题通常不出在它本身,而出在你用它的方式:std::string::c_str() 返回的指针不保证以 \0 结尾(除非你显式 push_back(0)),且 std::string 构造时若传入含 \0 的 raw buffer 和长度,必须用带长度的构造函数。
std::string 构造时若传入含 std::string 不是二进制安全容器,但问题通常不出在它本身,而出在你用它的方式:std::string::c_str() 返回的指针不保证以 \0 结尾(除非你显式 push_back(0)),且 std::string 构造时若传入含 \0 的 raw buffer 和长度,必须用带长度的构造函数。
立即学习“C++免费学习笔记(深入)”;
- 用
std::string s(buf);初始化(无长度参数)→ 遇到第一个\0就截断,TCP 包里的二进制数据或 UTF-8 中间字节被误判为结束 - 用
s.c_str()直接传给send()→ 长度按strlen()算,丢弃后续所有字节 - 把
recv()返回值当std::string长度却没 resize → 访问未初始化内存,行为未定义
正确做法是:用 std::vector<char></char> 做缓冲区,或用 std::string 时始终配合 size() 和 data()(C++17 起 data() 返回可写的指针)。










