2013-02-27 182 views
2

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

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

非常感谢!

#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; 

} 

回答

5

您需要检查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

+0

非常感谢,它的工作原理!是的,我知道循环会浪费CPU时间,但它只是测试套接字上的非阻塞的程序。 – user1016711 2013-02-27 09:56:17

+0

@ user1016711 - 让我看看一些爱,然后点击此答案旁边的大号复选标记。 – selbie 2013-02-27 10:15:15

5

我得到一个错误-1时,有中没有数据,但我希望得到EAGAIN错误。

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

+0

非常感谢! errno是EAGAIN。 – user1016711 2013-02-27 09:54:19