2016-09-02 1 views
0

Ich benutze nicht blockierende Buchse, um neue Verbindung zu erhalten. Aber der Code schlägt wiederholt auf accept() fehl.socket :: akzeptieren kontinuierlich zu EGAIN

int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); 
::bind(sockfd, bind_addr, static_cast<socklen_t>(sizeof(struct sockaddr_in6))); 
ret = ::listen(sockfd, SOMAXCONN); 

while (True) { 
    ::poll(&*pollfds_.begin(), pollfds_.size(), timeoutMs); 
    struct sockaddr_in6 addr; 
    bzero(&addr, sizeof addr); 
    socklen_t addrlen = static_cast<socklen_t>(sizeof *addr); 
    int connfd = ::accept4(sockfd, sockaddr_cast(addr), 
         &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC); 
} 

errno ist EAGAIN.

+0

Sie definieren 'connfd' zweimal, können Sie eine [MCVE]? – purplepsycho

+0

Verwenden Sie ipv6 ('sockaddr_in6') oder ipv4 (' :: accept4')? – purplepsycho

+0

@purplepsycho Ich kopiere eine weitere Zeile von meinem Projekt. – Sam

Antwort

2

Von der manpage zu accept(2):

EAGAIN oder EWOULDBLOCK

Die Buchse ist nicht blockierend markiert und keine Verbindungen vorhanden sind, in Kauf genommen werden. POSIX.1-2001 ermöglicht, dass für diesen Fall entweder ein Fehler zurückgegeben wird und diese Konstanten nicht den gleichen Wert haben müssen, sodass eine portable Anwendung nach beiden Möglichkeiten suchen sollte.

Dies bedeutet, dass der Anruf an accept erfolgt, bevor der Client verbunden wurde.

1

Bevor Sie accept anrufen, müssen Sie listen und bind anrufen. Aber Da Ihr Socket nicht blockiert, sollten Sie warten, bis der Client auf die Verbindung wartet. Sie können das mit select Funktion tun:

int sockfd = ::socket(family, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, IPPROTO_TCP); 

// addr is for accept call, sin for bind call 
struct sockaddr_in6 addr, sin; 
bzero(&addr, sizeof addr); 

// prepare sin to tell bind to listen on any connection on given port 
sin.sin6_family = family; 
sin.sin6_addr = in6addr_any; 
sin.sin6_port = htons(port); // choose port on which client could connect 
sin.sin6_scope_id = 0; 

// bind socket to interface 
if (::bind(sock, (struct sockaddr*) &sin, sizeof(sin)) < 0) 
{ 
    perror("bind"); 
} 

// listen for new connection 
if (::listen(sock, SOMAXCONN) < 0) 
{ 
    perror("socket"); 
} 

while (1) 
{ 
    fd_set conset; 
    FD_ZERO(&conset); 
    FD_SET(sockfd, &conset); 

    struct timeval timeout = {10, 0}; 
    int maxfd = sockfd; 

    // wait for new client 
    select(maxfd + 1, &conset, NULL, NULL, &timeout); 

    if (FD_ISSET(sockfd, &conset)) 
    { 
     // a new client is waiting 
     int connfd = ::accept(sockfd, &addr); 
     if (connfd < 0) 
     { 
      perror("accept"); 
     } 
     else 
     { 
      // do thing with new client 
     } 
    } 
    else 
    { 
     printf("no new client in last 10 seconds") 
    } 
} 
+0

Der Code vorher ist nur wichtig. Ich habe Pastencodes von Polling. – Sam