Socket with recv-timeout: What is wrong with this

2020-07-06 03:04发布

I'm trying to implement a socket with a recv timeout of 1 Second:

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);

Without 'setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv);' the calls to accept and recv work, but recv blocks.

With 'setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv);' the call to accept produces the error 'Resource temporarily unavailable'.

Can somebody please tell me what is wrong with this approach?

标签: c linux sockets
6条回答
闹够了就滚
2楼-- · 2020-07-06 03:30

Nothing is wrong... The error code EAGAIN (Resource temporarily unavailable) is exactly what you should get after the timeout expires!

查看更多
Luminary・发光体
3楼-- · 2020-07-06 03:36

You need one more closing parenthesis at each of these two lines.

- setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on);
+ setsockopt( sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
- setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv);
+ setsockopt( sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
查看更多
再贱就再见
4楼-- · 2020-07-06 03:41

Try using select() before calling recv() or accept().

select() takes an array of file descriptors (includinig sockets) and returns when at least one of them is ready to receive. It can also return on a timeout.

In linux you can also try poll() (not sure if Winsock provides this).

查看更多
男人必须洒脱
5楼-- · 2020-07-06 03:46

Which socket do you want to have the one-second timeout on? The one accepting connections, or the one established by accept()?

I'd assume the latter - so try setting the receive timeout on clientfd AFTER the accept returns. You can also get to where you need to be using select, but you shouldn't need to.

查看更多
太酷不给撩
6楼-- · 2020-07-06 03:47

This is little bit off topic, but I really want to share this solution to set recv timeout both on windows and unix. Maybe it's me, but it took me a lot of time to figure out why my program doesn't work and how to properly set timeout. Hope you find it useful. It sets timeout to 10 seconds.

For Windows:

DWORD sock_timeout = 10*1000;

For Unix:

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

For both:

setsockopt(socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&sock_timeout, sizeof(sock_timeout));
查看更多
三岁会撩人
7楼-- · 2020-07-06 03:56

Here's a snippet using 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);
查看更多
登录 后发表回答