在使用C语言进行的套接字编程中,如何在服务器上设置接受客户端建立连接的时间限制?

问题描述

我正在开发一个包含1个客户端和1个服务器的应用程序。

我希望服务器仅监听5秒钟以进行连接。如果客户端未尝试建立连接,则服务器应停止侦听并返回错误消息。如果客户端尝试建立连接,则服务器应接受该连接。

如果客户端未尝试建立连接,则服务器将永远监听。我希望服务器仅监听5秒钟,如何实现?

这是服务器端的输出-服务器永远在等待客户端:

image

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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...