2016-06-19 9 views
1

私は初めてLinuxでepollを使って遊んでいて、いくつかの奇妙な動作を見ています。具体的には、クライアントとソケットに接続すると、サーバ側でepoll_waitが発行する2つのイベントが表示されます。私が2回目の試みで受け入れを呼び出すと、私は「一時的に利用できません」というエラーが出ます。epollで2つのacceptイベントを見る

#include <stdio.h> 
#include <stdlib.h> 
#include <sys/socket.h> 
#include <sys/un.h> 
#include <unistd.h> 

const char* msg = "friendly ping"; 

int main(int argc, char** argv) { 
    if (argc != 2) { 
    fprintf(stderr, "Usage: %s <socket>\n", argv[0]); 
    exit(-1); 
    } 

    int sock = socket(AF_UNIX, SOCK_STREAM, 0); 
    if (sock < 0) { 
    perror("socket"); 
    exit(-1); 
    } 

    struct sockaddr_un addr; 
    addr.sun_family = AF_UNIX; 
    strncpy(addr.sun_path, argv[1], sizeof(addr.sun_path) - 1); 

    if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) { 
    perror("Error connecting"); 
    exit(-1); 
    } 

    write(sock, msg, strlen(msg)); 
    close(sock); 

    return 0; 
} 

サーバー・コードは以下の通りである:

は簡単なクライアントコードです

Calling epoll_wait 
Checking event for fd = 3 
Connection processed. 
Calling epoll_wait 
Checking event for fd = 3 
Error accepting connection: Resource temporarily unavailable 
#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/epoll.h> 
#include <sys/socket.h> 
#include <sys/un.h> 
#include <unistd.h> 

const int kMaxEvents = 100; 
const char *kSocketFile = "dummy_socket"; 

void MakeNonBlocking(int fd) { 
    int flags, s; 

    flags = fcntl (fd, F_GETFL, 0); 
    if (flags == -1) { 
    perror ("fcntl"); 
    exit(-1); 
    } 

    flags |= O_NONBLOCK; 
    s = fcntl (fd, F_SETFL, flags); 
    if (s == -1) { 
    perror ("fcntl"); 
    exit(-1); 
    } 
} 

void AcceptConnections(int sock, int epoll_fd) { 
    struct epoll_event event; 
    event.data.fd = sock; 
    event.events = EPOLLIN; 

    int insock = accept(sock, NULL, NULL); 
    if (insock < 0) { 
    perror("Error accepting connection"); 
    exit(-1); 
    } 

    MakeNonBlocking(insock); 

    int s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, insock, &event); 
    if (s < 0) { 
    perror("Epoll error adding accepted connection"); 
    exit(-1); 
    } 
    printf("Connection processed.\n"); 
} 

int main(void) { 
    int sock, efd, n; 
    struct sockaddr_un addr; 
    struct epoll_event event; 
    struct epoll_event *events; 
    char buf[1024]; 

    if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { 
    perror("Error creating socket."); 
    exit(-1); 
    } 

    addr.sun_family = AF_UNIX; 
    strncpy(addr.sun_path, kSocketFile, sizeof(addr.sun_path) - 1); 
    if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { 
    perror("Error binding name to socket"); 
    exit(-1); 
    } 

    if (listen(sock, SOMAXCONN) < 0) { 
    perror("Error listening on socket"); 
    exit(-1); 
    } 

    MakeNonBlocking(sock); 

    if ((efd = epoll_create1(0)) < 0) { 
    perror("Epoll initialization error"); 
    exit(-1); 
    } 

    event.data.fd = sock; 
    event.events = EPOLLIN; 
    if (epoll_ctl(efd, EPOLL_CTL_ADD, sock, &event) < 0) { 
    perror("Epoll error adding socket"); 
    exit(-1); 
    } 

    events = (struct epoll_event*) calloc(kMaxEvents, sizeof(event)); 
    if (!events) { 
    perror("Error allocating event buffers"); 
    exit(-1); 
    } 

    while(1) { 
    printf("Calling epoll_wait\n"); 
    if ((n = epoll_wait(efd, events, kMaxEvents, -1)) == -1) { 
     perror("epoll_wait failure"); 
     exit(-1); 
    } 

    for (int i = 0; i < n; ++i) { 
     printf("Checking event for fd = %d\n", events[i].data.fd); 
     if (sock == events[i].data.fd) { 
     AcceptConnections(sock, efd); 
     continue; 
     } 

     int count = read(events[i].data.fd, buf, 100); 
     if (count == 0) { 
     close(events[i].data.fd); 
     } 
     write(1, buf, count); 
    } 
    } 

    free(events); 
    close(efd); 
    close(sock); 
    unlink(kSocketFile); 
    return 0; 
} 

私は、サーバーを実行して、私が手にクライアントに接続

つまり、リスニングソケットに2つのイベントがあります。何か案は? AcceptConnectionsを変更、修正するには

+0

これをチェックしたいのですが、ランタイムエラーが発生します: 'ソケットへのエラーバインディング:操作が許可されていません。 ' – Myst

答えて

1

void AcceptConnections(int sock, int epoll_fd) { 
    struct epoll_event event; 
    event.events = EPOLLIN; 

    int insock = accept(sock, NULL, NULL); 
    if (insock < 0) { 
    perror("Error accepting connection"); 
    exit(-1); 
    } 

    // This is the important change. 
    event.data.fd = insock; 

    MakeNonBlocking(insock); 

    int s = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, insock, &event); 
    if (s < 0) { 
    perror("Epoll error adding accepted connection"); 
    exit(-1); 
    } 
    printf("Connection processed.\n"); 
} 

epollは...

問題は、AcceptConnectionsにイベントを登録する方法と、時々面白いです。

epollは、二つの異なるfd値、event.data.fd(ユーザ不透明なデータ値)に1とepoll_ctl関数呼び出しの開始に他の(イベント制御fd)を受け付けます。

event.data.fdは何もすることができ、そしてそれはあなたがあなたのイベントループに読み、実際のデータです...

...あなたの元のコードでは、あなたはリスニングソケットの代わりに、クライアントに設定しましたソケット。

クライアントソケットが読み込み可能なデータの準備ができているときに、イベントではなくクライアントソケットのソケットをリスニングevent.data.fdポインティングを上げています。

イベント(クライアントソケットの場合)をクリアしないので、設定したデータ(リスニングソケットfd)で繰り返し発生します。

Good Luck!

関連する問題