解决:阻塞socket连接成功情况下recv返回值为-1
引言
直入正题 在前几天进行Web服务器的编写时遇到了这么一个奇怪的问题 就是在socket连接成功且在epoll触发可读事件以后recv却没有收到任何东西 返回-1 在解决后遂记录一篇博客
首先在刚开始我使用了ET非阻塞,所以在出现recv返回值为-1 且 errno等于EAGAIN时当然首先想到的就是一次没有收到这个包 循环接收即可 但当我改为循环接收时却发现每一次都没有收到这个包 即陷入了死循环 这就很奇怪了, 这个时候鸭鸭学长告诉要不改成LT 但是不recv看看包是否发到,结果发现包确实是接收到了, 但当我加上recv时 心想应该出现阻塞或接收成功时却出现了死循环的情况,这是阻塞啊,奇怪奇怪, 怎么会出现这种情况呢,这个时候突然想起recv的第四个参数有一个是可以使本次recv成为非阻塞的,难道是参数的问题,一看socket类的构造函数,顺手把第四个参数的默认参数写成了-1,这个时候问题的答案也就水落石出了,-1的补码为1111 1111 1111 1111,下面是recv的第四个参数
/* Bits in the FLAGS argument to `send', `recv', et al. */
enum
{
MSG_OOB = 0x01, /* Process out-of-band data. */
#define MSG_OOB MSG_OOB
MSG_PEEK = 0x02, /* Peek at incoming messages. */
#define MSG_PEEK MSG_PEEK
MSG_DONTROUTE = 0x04, /* Don't use local routing. */
#define MSG_DONTROUTE MSG_DONTROUTE
#ifdef __USE_GNU
/* DECnet uses a different name. */
MSG_TRYHARD = MSG_DONTROUTE,
# define MSG_TRYHARD MSG_DONTROUTE
#endif
MSG_CTRUNC = 0x08, /* Control data lost before delivery. */
#define MSG_CTRUNC MSG_CTRUNC
MSG_PROXY = 0x10, /* Supply or ask second address. */
#define MSG_PROXY MSG_PROXY
MSG_TRUNC = 0x20,
#define MSG_TRUNC MSG_TRUNC
MSG_DONTWAIT = 0x40, /* Nonblocking IO. */
#define MSG_DONTWAIT MSG_DONTWAIT
MSG_EOR = 0x80, /* End of record. */
#define MSG_EOR MSG_EOR
MSG_WAITALL = 0x100, /* Wait for a full request. */
#define MSG_WAITALL MSG_WAITALL
MSG_FIN = 0x200,
#define MSG_FIN MSG_FIN
MSG_SYN = 0x400,
#define MSG_SYN MSG_SYN
MSG_CONFIRM = 0x800, /* Confirm path validity. */
#define MSG_CONFIRM MSG_CONFIRM
MSG_RST = 0x1000,
#define MSG_RST MSG_RST
MSG_ERRQUEUE = 0x2000, /* Fetch message from error queue. */
#define MSG_ERRQUEUE MSG_ERRQUEUE
MSG_NOSIGNAL = 0x4000, /* Do not generate SIGPIPE. */
#define MSG_NOSIGNAL MSG_NOSIGNAL
MSG_MORE = 0x8000, /* Sender will send more. */
#define MSG_MORE MSG_MORE
MSG_WAITFORONE = 0x10000, /* Wait for at least one packet to return.*/
#define MSG_WAITFORONE MSG_WAITFORONE
MSG_BATCH = 0x40000, /* sendmmsg: more messages coming. */
#define MSG_BATCH MSG_BATCH
MSG_ZEROCOPY = 0x4000000, /* Use user data in kernel path. */
#define MSG_ZEROCOPY MSG_ZEROCOPY
MSG_FASTOPEN = 0x20000000, /* Send data in TCP SYN. */
#define MSG_FASTOPEN MSG_FASTOPEN
MSG_CMSG_CLOEXEC = 0x40000000 /* Set close_on_exit for file
descriptor received through
SCM_RIGHTS. */
#define MSG_CMSG_CLOEXEC MSG_CMSG_CLOEXEC
};
也就是说在参数设置-1的情况下阴差阳错的注册了第四个参数的所有选项, 其中的MSG_DONTWAIT使得阻塞情况下陷入了循环接收 , MSG_OOB带外数据接收使得触发可读事件却无法正常接收数据,至此这个问题就解决了。
同时我们也可以看出在非阻塞的情况下并非在errno == EAGAIN的情况就是可以忽略的