sockets - 在使用C语言的socket编程中,如何设置服务器接受客户端建立连接的时间限制?
问题描述
我正在开发一个涉及 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);
}
解决方案
You are using the listening socket in blocking mode, so accept()
will block the calling thread until a client connects. To use a timeout, call select()
or (e)poll()
first to wait for the listening socket to enter a readable state indicating a connection is pending BEFORE you then call accept()
.
For example:
...
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, 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, (SA*)&cli, &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, 1, 5000)) <= 0)
{
if (res < 0)
printf("epoll_ctl failed...\n");
else
printf("Time out...\n");
exit(0);
}
close(epfd);
connfd = accept(sockfd, (SA*)&cli, &len);
...
Either way, note that there is a very small race condition created by these scenarios. If the client connects and then disconnects before accept()
is called, accept()
may block waiting for a new pending connection, or it may return a valid file descriptor that fails on subsequent I/O calls. There is no guarantee one way or the other.
To solve the race condition, you can either:
put the listening socket into non-blocking mode. If
select()
reports the listening socket has a pending connection, butaccept()
is not able to accept it right away, then you can act accordingly.use
accept()
on a listening socket in blocking mode, as you originally were, but usealert()
to scheduleaccept()
to be interrupted if it doesn't exit before 5 seconds have elapsed. See this answer for an example.
推荐阅读
- emeditor - emeditor的marco可以模拟多行选择吗?
- android - http url 连接设置中的异常
- spring-boot - Spring Boot 需要很长时间才能引导
- angular - Angular i18n 后初始翻译
- angular - Alertify 在 Angular 中未定义问题:12.0.4
- javascript - selenium 中的函数,一旦出现就返回所需的元素
- python - 使用 BeautifulSoup 抓取数据时出错
- amazon-web-services - 将 Lambda 函数与位于不同 AWS 账户中的 CloudFront 分配结合使用
- sql - Redshift - generate_series 解决方法?
- sql - 如何解决sql中列的float类型的问题?