带有recv-timeout的套接字:这段代码有什么问题?

时间:2008-12-25 23:09:43

标签: c linux sockets

我正在尝试实现一个recv超时为1秒的套接字:

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

没有'setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,& tv,sizeof(tv);'调用接受和recv工作,但recv阻止。

使用'setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,& tv,sizeof(tv);'接受调用会产生错误'资源暂时不可用'。

有人可以告诉我这种方法有什么问题吗?

6 个答案:

答案 0 :(得分:6)

你希望哪个套接字有一秒超时?接受连接的那个,或者是accept()建立的连接?

我假设后者 - 所以尝试在accept返回后在clientfd上设置接收超时。你也可以到达你需要使用select的地方,但你不需要。

答案 1 :(得分:5)

这有点偏离主题,但我真的想分享这个解决方案来在windows和unix上设置recv超时。也许是我,但我花了很多时间才弄清楚为什么我的程序不起作用以及如何正确设置超时。希望你觉得它有用。 它将超时设置为10秒。

对于Windows:

DWORD sock_timeout = 10*1000;

对于Unix:

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

对于两者:

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

答案 2 :(得分:4)

以下是使用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);

答案 3 :(得分:1)

没有错......错误代码EAGAIN(资源暂时不可用)正是超时到期后你应该得到的!

答案 4 :(得分:1)

这两行中每一行都需要一个右括号。

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

答案 5 :(得分:0)

在调用recv()或accept()之前尝试使用select()。

select()接受一个文件描述符数组(includinig sockets),并在其中至少有一个准备好接收时返回。它也可以在超时时返回。

在linux中你也可以尝试poll()(不确定Winsock是否提供了这个)。