2013-02-27 221 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