下面的STCP代码片段展示了我观察到的一个问题。 它在调用recv时阻塞,直到有数据可读,然后它处理接收到的数据并再次调用recv,recv要么返回更多的数据(或错误),要么阻塞。 如果发生了错误,recv将返回一个-1,错误代码被设置在errno变量中。 你觉得这段代码还行吗?
while (1) { cBytes = recv (socks1, buffer, BUFFERLEN, 0); if (cBytes == -1) { perror ("Unexpected error at recv"); exit (errno); } else printf ("number of bytes received : %dn", cBytes); } |
该代码假设远程对等体永远不会优雅地关闭连接。 当远程对等体进行优雅关闭时,也就是调用关闭或关闭函数时,recv通过返回零字节来向本地应用程序表明这一点。 随后对recv的调用将继续返回零字节。 其结果是,现在的代码处于一个紧密的循环中,什么也不做。 例如
收到的字节数:8 收到的字节数:57 收到的字节数:16 收到的字节数:1 收到的字节数:1 收到的字节数:0 收到的字节数:0 收到的字节数:0 收到的字节数:0 收到的字节数:0 .. . . . |
即使应用协议规定远程对等体永远不会优雅地关闭连接,你也不能保证连接永远不会被优雅地关闭。 远程应用程序可能有一个bug,或者远程TCP协议栈可能会在应用程序进程终止时进行优雅关闭。 也可能是其他应用程序建立了一个连接,然后在没有得到预期的响应时关闭了它。 安全审计(或恶意用户)进行端口扫描或banner抓取也可能会做一个优雅的关闭。 底线是,你总是要处理零字节的情况。
while (1) { cBytes = recv (socks1, buffer, BUFFERLEN, 0); if (cBytes <= 0) { if (cBytes < 0) { perror ("Unexpected error at recv"); exit (errno); } else { printf ("received closen"); close (socks1); exit (0); } } else printf ("number of bytes received : %dn", cBytes); } |
收到的字节数:28 收到的字节数:2 收到的字节数:58 挨近 |