Linux 使用非阻塞套接字接收
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15108122/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
recv with non-blocking socket
提问by user1016711
I am trying to implement non-blocking for socket recv
and the problem is that I got an error -1 when there in no data but I expect to get EAGAIN
error.
我正在尝试为套接字实现非阻塞,recv
问题是当没有数据时我收到错误 -1 但我希望得到EAGAIN
错误。
Socket is set definitely to non-blocking state, I checked flags = fcntl(s, F_GETFL, 0)
for O_NONBLOCK
flag.
套接字绝对设置为非阻塞状态,我检查flags = fcntl(s, F_GETFL, 0)
了O_NONBLOCK
标志。
Thanks a lot in advance!
非常感谢!
#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;
}
采纳答案by selbie
You need to check errno
, not the length value to get the reason why the socket failed to return data. Also, EWOULDBLOCK
is the other error code you should check for in addition to EAGAIN
. Change your while loop as follows:
您需要检查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);
}
Of course this infinite loop will get into a CPU wasting busy cycle while it's waiting for data. There are a variety of ways to be notified of data arriving on a socket without having to call recv()
in a spin loop. This includes select
and poll
calls.
当然,这个无限循环会在等待数据时进入一个 CPU 浪费繁忙的周期。有多种方法可以通知数据到达套接字,而无需调用recv()
自旋循环。这包括select
和poll
调用。
回答by user207421
I got an error -1 when there in no data but I expect to get EAGAIN error.
当没有数据时,我收到错误 -1,但我希望收到 EAGAIN 错误。
-1 tells you there is an error. errno
tells you what the error was.
-1 告诉你有错误。errno
告诉你错误是什么。