5

ソケットにノンブロッキングを実装しようとしてrecvいますが、データがないときにエラー-1が発生するという問題がありますが、エラーが発生することが予想されEAGAINます。

ソケットは確実に非ブロッキング状態に設定されているので、フラグを確認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;

}
4

2 に答える 2

6

データがない場合にエラー-1が発生しましたが、EAGAINエラーが発生すると予想されます。

-1は、エラーがあることを示します。errnoエラーが何であったかを教えてくれます。

于 2013-02-27T09:34:20.043 に答える
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呼び出しが含まれます。

于 2013-02-27T09:34:39.107 に答える