从昨天上午到10分钟之前都在调试程序中的一个BUG,问题的精简描述是这样的:
一个经典的C/S模型,客户端异步的向服务器端发送一条指令,服务器端接收到该指令后向客户端发送一个int型数据len。这个过程重复的次数是随机的,并且有时候操作频繁。
对于上述过程的实现并不困难,在本地测试C/S端也并无异常。但是进行远程测试就出现异常:服务器端发送的len正常,但是客户端接收的数据有时候会为0。
经历了长时间的调试和分析后,终将问题锁定在recv()。该函数的原型如下:
#include < sys/types.h > #include < sys/socket.h > ssize_t recv(int sockfd, void *buf, size_t len, int flags);
这个函数前三个参数的含义与read()大致相同,只不过recv()中的sockfd代表套接字描述符。除此之外,还有flags参数,一般被指定为0。而恰恰正是这种默认赋值才导致上述问题的产生,该标志可取多个值,其中一个值为MSG_WAITALL。这个标志告知内核在未读入指定字节len大小的数据之前不要将recv()返回。当为这个flags指定了该值后,结果正常。不过,该函数还是会在下述三种情况下提前返回:
1.连接被终止或套接字发生异常
2.接收了一个与之前类型不同的数据
3.捕获了一个信号
这三种情况都属于异常情况,跟上述问题无关。