recv与非阻塞套接字

我想实现无阻塞的套接字recv和问题是,我得到一个错误-1当没有数据,但我希望得到EAGAIN错误。

套接字设置为非阻塞状态,我为O_NONBLOCK标志检查了flags = fcntl(s, F_GETFL, 0)

提前感谢!

 #include <arpa/inet.h> #include <linux/if_packet.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <net/if.h> #include <netinet/ether.h> #include <unistd.h> #include <fcntl.h> #include <asm-generic/errno-base.h> #include <assert.h> #define ETH_FRAME_LEN_MY 1400 void print(void *buf, int length) { int i; for (i = 0; i < length; ++i) putchar(((char *)buf)[i]); printf("\n"); } int main(){ int flags, s, r, err; struct sockaddr_ll socket_addr; char ifName[IFNAMSIZ] = "eth0"; struct ifreq if_idx; struct ifreq if_mac; s = socket(PF_PACKET, SOCK_RAW, htons(0x88b6)); if (s == -1) { perror("socket"); } flags = fcntl(s,F_GETFL,0); assert(flags != -1); fcntl(s, F_SETFL, flags | O_NONBLOCK); flags = fcntl(s, F_GETFL, 0); if ((flags & O_NONBLOCK) == O_NONBLOCK) { printf("it's nonblocking"); } else { printf("it's blocking."); } /* Get the index of the interface to send on */ memset(&if_idx, 0, sizeof(struct ifreq)); strncpy(if_idx.ifr_name, ifName, IFNAMSIZ-1); if (ioctl(s, SIOCGIFINDEX, &if_idx) < 0) {perror("SIOCGIFINDEX");} memset(&socket_addr, 0, sizeof(socket_addr)); socket_addr.sll_ifindex = if_idx.ifr_ifindex; socket_addr.sll_protocol = htons(0x88b5); socket_addr.sll_family = PF_PACKET; socket_addr.sll_pkttype = PACKET_OUTGOING; r = bind(s, (struct sockaddr*)&socket_addr, sizeof(socket_addr)); if ( r < 0) { perror("bind"); } void* buffer = (void*)malloc(ETH_FRAME_LEN_MY); /*Buffer for ethernet frame*/ int length = 0; /*length of the received frame*/ while(1){ printf("1\n"); length = recv(s, buffer, ETH_FRAME_LEN_MY, 0); printf("2\n"); if (length < 0) { if (length == -EAGAIN) printf("non-blocking succeeded\n"); else printf("error code %i\n", length); } //printf ("buffer %s\n", buffer); print(buffer, length); } return 0; } 

Solutions Collecting From Web of "recv与非阻塞套接字"

您需要检查errno ,而不是长度值以获取套接字未能返回数据的原因。 此外, EWOULDBLOCK是除了EAGAIN之外还应该检查的其他错误代码。 改变你的while循环如下:

 while(1) { int err; printf("1\n"); length = recv(s, buffer, ETH_FRAME_LEN_MY, 0); err = errno; // save off errno, because because the printf statement might reset it printf("2\n"); if (length < 0) { if ((err == EAGAIN) || (err == EWOULDBLOCK)) { printf("non-blocking operation returned EAGAIN or EWOULDBLOCK\n"); } else { printf("recv returned unrecoverable error(errno=%d)\n", err); break; } } //printf ("buffer %s\n", buffer); print(buffer, length); } 

当然这个无限循环会在等待数据的时候进入CPU浪费繁忙的周期。 有多种方式可以通知到达套接字的数据,而无需在旋转循环中调用recv() 。 这包括selectpoll呼叫。

我得到一个错误-1,当没有数据,但我期望得到EAGAIN错误。

-1告诉你有一个错误。 errno告诉你错误是什么。