问题描述
我正在开发一个包含1个客户端和1个服务器的应用程序。
我希望服务器仅监听5秒钟以进行连接。如果客户端未尝试建立连接,则服务器应停止侦听并返回错误消息。如果客户端尝试建立连接,则服务器应接受该连接。
如果客户端未尝试建立连接,则服务器将永远监听。我希望服务器仅监听5秒钟,如何实现?
这是服务器端的输出-服务器永远在等待客户端:
void reception(){
int sockfd,connfd,len;
struct sockaddr_in servaddr,cli;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if (sockfd == -1) {
printf("socket creation Failed...\n");
exit(0);
}
else
printf("Socket successfully created..\n");
bzero(&servaddr,sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(PORT);
if ((bind(sockfd,(SA*)&servaddr,sizeof(servaddr))) != 0) {
printf("socket bind Failed...\n");
exit(0);
}
else
printf("Socket successfully binded..\n");
if ((listen(sockfd,5)) != 0) {
printf("Listen Failed...\n");
exit(0);
}
else
printf("Server listening..\n");
len = sizeof(cli);
connfd = accept(sockfd,(SA*)&cli,&len);
/*
Some function should be added at this point to
stop the server from listening after 5 seconds
*/
if (connfd < 0) {
printf("server acccept Failed...\n");
exit(0);
}
else
printf("server acccept the client...\n");
receive(connfd);
close(sockfd);
}
解决方法
您正在以阻塞模式使用侦听套接字,因此accept()
将阻塞调用线程,直到客户端连接为止。要使用超时,请先调用select()
或(e)poll()
以等待侦听套接字进入可读状态,指示连接处于挂起状态,然后再调用accept()
。
例如:
...
fd_set rds;
FD_ZERO(&rds);
FD_SET(sockfd,&rds);
struct timeval timeout;
timeout.tv_sec = 5;
timeout.tv_usec = 0;
int res;
if ((res = select(sockfd+1,&rds,NULL,&timeout)) <= 0)
{
if (res < 0)
printf("select failed...\n");
else
printf("Time out...\n");
exit(0);
}
connfd = accept(sockfd,(SA*)&cli,&len);
...
...
struct pollfd pfd;
pfd.fd = sockfd;
pfd.events = POLLIN;
pfd.revents = 0;
int res;
if ((res = poll(&pfd,1,5000)) <= 0)
{
if (res < 0)
printf("poll failed...\n");
else
printf("Time out...\n");
exit(0);
}
connfd = accept(sockfd,&len);
...
int epfd = epoll_create(1);
if (epfd < 0)
{
printf("epoll_create failed...\n");
exit(0);
}
struct epoll_event ev;
ev.events = EPOLLIN;
ev.data.fd = sockfd;
if (epoll_ctl(epfd,EPOLL_CTL_ADD,sockfd,&ev) < 0)
{
printf("epoll_ctl failed...\n");
exit(0);
}
struct epoll_event event;
int res;
if ((res = epoll_wait(epfd,&event,5000)) <= 0)
{
if (res < 0)
printf("epoll_ctl failed...\n");
else
printf("Time out...\n");
exit(0);
}
close(epfd);
connfd = accept(sockfd,&len);
...
无论哪种方式,请注意,这些方案创建的竞争条件非常小。如果客户端在调用accept()
之前先连接然后断开连接,则accept()
可能阻止等待新的挂起连接,或者 返回一个有效的文件描述符,该文件描述符在后续的I / O调用中失败。无法保证一种方法。
要解决比赛条件,您可以:
-
将侦听套接字置于非阻塞模式。如果
select()
报告监听套接字有一个挂起的连接,但是accept()
无法立即接受它,那么您可以采取相应措施。 -
像以前一样在阻塞模式下在侦听套接字上使用
accept()
,但是如果alert()
在5之前没有退出,则使用accept()
安排campaign
被中断秒已过去。有关示例,请参见this answer。