处理 POSIX 套接字读取() 错误

Handling POSIX socket read() errors

本文关键字:错误 读取 POSIX 套接字 处理      更新时间:2023-10-16

目前我正在实现一个简单的客户端-服务器程序,该程序仅具有读/写的基本功能。

但是我注意到,例如,如果我的服务器调用 write() 来回复我的客户端,并且如果我的客户端没有相应的 read() 函数,我的服务器程序将挂在那里。

目前,我正在考虑使用一个简单的计时器来定义超时计数,然后在某个计数后断开客户端的连接,但我想知道是否有更优雅/或标准的方式来处理此类错误?

有两种常规方法可以防止服务器阻塞和单个服务器实例处理多个客户端:

  • 使用 POSIX 线程处理每个客户端的连接。如果一个线程由于错误的客户端而阻塞,其他线程仍将继续运行。如果远程客户端刚刚消失(崩溃、网络关闭等),那么 TCP 堆栈迟早会发出超时信号,并且被阻止的write操作将失败并出错。
  • 将非阻塞 I/O 与轮询机制一起使用,例如 select(2)poll(2) .但是,使用轮询调用进行编程非常困难。使用fcntl(2)使网络套接字不阻塞,如果套接字上的正常write(2)read(2)会阻塞,则会返回EAGAIN错误。您可以使用 select(2)poll(2) 来等待套接字上发生某些事情,并具有可调节的超时期限。例如,等待套接字变为可写,意味着当有足够的套接字发送缓冲区空间时,您将收到通知,例如,先前写入的数据被刷新到客户端计算机 TCP 堆栈。

如果客户端不再从套接字读取,它应该使用 close 关闭套接字。如果您不想这样做,因为客户端可能仍然想要写入套接字,那么您至少应该用 shutdown(fd, SHUT_RD) 关闭读取的一半。

这将对其进行设置,以便服务器在写入调用上获得EPIPE

如果您不控制客户端...如果您未编写的随机客户端可以连接,则服务器应处理主动尝试恶意的客户端。客户端恶意的一种方法是尝试强制服务器挂起。您应该结合使用非阻塞套接字和您描述的超时机制来防止这种情况发生。

通常,您应该编写服务器和客户端如何通信的协议,以便在另一端不读取时,服务器或客户端都不会尝试写入套接字。这并不意味着您必须紧密同步它们或任何东西。但是,例如,HTTP的定义方式是,任何一方都很清楚另一方是否真的期望他们在协议中的任何给定点写入任何内容。