2008-12-25 3 views
9

Ich versuche, eine Buchse mit einem recv Timeout von 1 Sekunde zu implementieren:Socket mit Recv-Timeout: Was ist falsch an diesem Code?

int sockfd; 
struct sockaddr_in self; 
struct sockaddr_in client_addr; 
int addrlen=sizeof(client_addr); 
ssize_t nBytes; 

sockfd = socket(AF_INET, SOCK_STREAM, 0); 

self.sin_family = AF_INET; 
self.sin_port = htons(PORT); 
self.sin_addr.s_addr = INADDR_ANY; 

int on = 1; 
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on); 

// 1 Sec Timeout 
tv.tv_sec = 1; 
tv.tv_usec = 0; 
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv); 

bind(sockfd, (struct sockaddr*)&self, sizeof(self)); 

listen(sockfd, 20); 

clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addrlen); 

nBytes = recv(clientfd, buffer, MAXBUF-1, 0); 

Ohne 'setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, & tv, sizeof (tv),' die Anrufe und recv zu akzeptieren Arbeit, aber recv Blöcke

Mit. 'setsockopt (sockfd, SOL_SOCKET, SO_RCVTIMEO, & tv, sizeof (tv);' erzeugt der Anruf zu akzeptieren, den Fehler 'Resource temporarily unavailable'

Kann jemand bitte sagen. mir was ist falsch mit diesem Ansatz?

+0

Haben Sie versucht, die setsockopt bewegen() aufrufen, um nach der accept()? – paxdiablo

+0

gelten die auf dem abhörenden Socket (sockfd) festgelegten Optionen für die von accept (clientfd) erstellten Sockets? – Cogsy

Antwort

0

Versuchen Sie es mit select(), bevor Sie recv() oder accept() aufrufen.

select() nimmt ein Array von Dateideskriptoren (einschließlich Sockets) und gibt zurück, wenn mindestens einer davon bereit zum Empfang ist. Es kann auch nach einer Zeitüberschreitung zurückkehren.

In Linux können Sie auch versuchen, poll() (nicht sicher, ob Winsock dies bietet).

+0

Nein, tut es nicht. –

4

Hier ein Ausschnitt mit select:

FD_ZERO(&masterfds); 
FD_SET(sockfd,&masterfds); 
memcpy(&readfds,&masterfds,sizeof(fd_set)); 
timeout.tv_sec = 2; 
timeout.tv_usec = 0; 
if (select(sockfd+1, &readfds, NULL, NULL, &timeout) < 0) 
{ 
    printf("select error"); 
    exit(1); 
} 

if (FD_ISSET(sockfd, &readfds)) 
{ 
    //printf("Read from socket\n"); 
    // read from the socket 
    res = recvfrom(sockfd, (char *)hdrbuf, sizeof(hdrbuf), MSG_PEEK, recvaddr, address_len); 
} 
else 
{ 
    // the socket timedout 
    //printf("Socket timeout started=%d\n",packets_started); 
6

Welche Buchse haben Sie auf die Ein-Sekunden-Zeit haben? Derjenige, der Verbindungen annimmt, oder der, der durch accept() hergestellt wird?

Ich würde letzteres annehmen - also versuchen Sie, das Empfangs-Timeout auf clientfd einzustellen, nachdem das Akzeptieren zurückkehrt. Sie können auch dorthin gelangen, wo Sie auswählen müssen, aber das sollten Sie nicht tun müssen.

+0

Ich hatte auch eine Timeout-Anforderung. und deine Lösung hat +1 geholfen. Verwenden Sie das Zeitlimit für den neuen Verbindungsdeskriptor. – RootPhoenix

1

Nichts ist falsch ... Der Fehlercode EAGAIN (Ressource vorübergehend nicht verfügbar) ist genau das, was Sie erhalten sollten, nachdem die Zeit abgelaufen ist!

1

Sie benötigen eine weitere schließende Klammer an jeder dieser beiden Zeilen.

5

Dies ist ein wenig off topic, aber ich möchte diese Lösung teilen, um recv Timeout sowohl auf Windows als auch auf Unix zu setzen. Vielleicht bin ich es, aber ich brauchte viel Zeit, um herauszufinden, warum mein Programm nicht funktioniert und wie man das Timeout richtig einstellt. Ich hoffe, Sie finden es nützlich. Es setzt Timeout auf 10 Sekunden.

Für Windows:

DWORD sock_timeout = 10*1000; 

Für Unix:

const struct timeval sock_timeout={.tv_sec=10, .tv_usec=0}; 

Für beide:

setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&sock_timeout, sizeof(sock_timeout));