English 中文(简体)
带有接收超时的套接字:这个代码有什么问题?
原标题:
  • 时间:2008-12-25 23:09:42
  •  标签:

我正在尝试实现一个具有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);,accept 和 recv 的调用可以工作,但 recv 会阻塞。

使用setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));时,对accept的调用会产生错误“资源暂时不可用”。

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

问题回答

你想在哪个套接字上设置一秒超时时间?接受连接的套接字,还是由accept()建立的套接字?

我会假定后者-因此,在accept()返回后尝试设置clientfd上的接收超时。您还可以使用select()到达所需的位置,但您不应该需要。

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.

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

这是一个使用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
");
    // 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
",packets_started);

没问题……错误代码EAGAIN(资源暂时不可用)恰好是超时到期后应该得到的!

你需要在这两行末尾加上一个括号。

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

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

select()接受一个文件描述符数组(包括套接字),并在至少一个文件描述符可以接收时返回。它也可以在超时时返回。

在Linux中,您也可以尝试使用poll()(不确定Winsock是否提供此功能)。





相关问题
热门标签