我试图实现一个接收超时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()建立的人?
我会假设后者 – 所以尝试在接受返回后设置clientfd上的接收超时。 你也可以到你需要使用select的地方,但是你不需要。
这是有点题外话,但我真的想分享这个解决方案设置在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));
这是一个使用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);
什么是错的…错误代码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是否提供了这个)。