真实面经题目 · 原创解析
单进程服务器中某个客户端不调用 recv 时,阻塞和非阻塞模式会怎样?
客户端不调用 recv 时,服务端发送缓冲区会逐渐积压;阻塞模式可能卡住整个单进程服务,非阻塞模式会返回 EAGAIN,需要事件驱动和背压处理。
出现于:网易 · C/C++
真实面经题目 · 原创解析
客户端不调用 recv 时,服务端发送缓冲区会逐渐积压;阻塞模式可能卡住整个单进程服务,非阻塞模式会返回 EAGAIN,需要事件驱动和背压处理。
如果某个客户端应用层不读数据,它的接收缓冲区会满,TCP 窗口变小甚至变成 0。服务端继续 send 时,内核发送缓冲区也会积压。阻塞 socket 下,send 可能阻塞,单进程模型会被这个慢客户端拖住,影响其他连接;非阻塞 socket 下,send 会返回 EAGAIN 或只写入部分数据,服务端需要保存未发送数据,等可写事件再继续,同时设置超时、限流和断开慢连接策略。
客户端不调用 recv,不代表网络立刻断开,而是客户端内核接收缓冲区逐渐填满。接收窗口变小后,服务端可发送的数据量会被 TCP 流控限制。
单进程阻塞模型中,如果对这个客户端 send 时卡住,进程就无法继续处理其他客户端的读写事件,慢连接会放大成整体服务不可用。
非阻塞 socket 发送不了时通常返回 EAGAIN/EWOULDBLOCK,或者只写入部分字节。应用层要记录剩余数据,而不是认为连接必然失败。
正确做法是用 select、poll、epoll 等机制监听可写事件,缓冲待发送数据,在 socket 可写时继续 flush,同时避免无限缓存。
工程上要设置每连接输出缓冲区上限、写超时、心跳检测、丢弃低优先级消息或主动断开,防止一个客户端消耗过多内存和调度资源。
保存未发送数据,注册可写事件,等 socket 可写后继续发送,并限制缓冲区大小。
接收端缓冲区满且应用不读取时,会通告很小或为 0 的窗口,发送端只能等待窗口更新。
设置写缓冲上限、写超时、限速、消息降级和主动断开策略,保护服务整体吞吐。