我意识到我至少会得到一个答案,即“(重新)编写代码以使其不会挂起”,但假设我们还没有生活在那个闪亮的快乐乌托邦中......
在我们的嵌入式系统中,我们有一个很大的 SDK,包括一个 Web 服务器 (Boa),它是用户交互的主要方法。
在月相的某些阶段,某些事情可能会导致 Web 服务器挂起或以其他方式卡住,从而使进程看起来正常运行(未崩溃/死机/使用 100% CPU)但不为任何 Web 服务页。
所以,问题是,我们如何测试/检测这种情况?
要测试服务器是否挂起,请创建一个 TCP 套接字并连接到80
IP 地址127.0.0.1
(环回地址)上的端口。然后通过套接字发送以下文本
GET / HTTP/1.1\r\n\r\n
大多数服务器会将其解释为对index.html
. 或者,您可以实现一个未记录的 URL 进行测试(允许更短的预定响应),例如
GET /test/fdoaoqfaf12491r2h1rfda HTTP/1.1\r\n\r\n
然后,您需要从服务器读取响应。这涉及使用select
合理的超时来确定是否有任何数据从服务器返回,如果是,则recv
用于读取数据。来自服务器的响应将包含一个标头,后跟内容。标题由文本行组成,标题末尾有一个空行。行以 结尾\r\n
,所以标题的结尾是\r\n\r\n
。
获取内容涉及调用select
,recv
直到recv
返回 0。这假定服务器将发送响应然后关闭套接字。一些复杂的服务器将打开一个套接字以允许多个请求通过同一个套接字。一个简单的嵌入式服务器不应该这样做。(如果您的服务器尝试对多个请求使用同一个套接字,那么您需要弄清楚如何关闭该功能。)
这一切都很好,但你真的需要重写你的代码,这样它就不会挂起。
问题的最可能原因是服务器有一堆悬空套接字,即从未正确清理过的客户端连接。悬空套接字最终会阻止服务器接受更多的连接,要么是因为服务器对打开的连接数有限制,要么是因为运行服务器的进程用尽了它的所有文件描述符。
首先要检查的是 TCP 超时值。我从事的一个项目的默认超时为 5 小时,这意味着悬空套接字保持打开 5 小时。合理的超时时间是 1 分钟。
然后你需要创建一个故意行为不端的客户端。客户可以通过
第一种情况应该由 TCP 超时来处理。其他两个需要由服务器代码正确处理。优雅和突然的套接字关闭是通过 SO_LINGER 选项ioctl
和shutdown
函数来控制的。客户端出现异常后,检查服务器进程中打开的文件描述符的数量,以验证服务器是否正确处理了这种情况。