2010-08-09 94 views
16

我有一个事件驱动的网络服务器程序。该程序接受来自其他主机上其他进程的连接。同一个远程IP上的不同端口可能会有很多短暂的连接。同时使用accept()和select()?

目前,我有一个while(1)循环,它调用accept(),然后产生一个线程来处理新的连接。读取消息后,每个连接都将关闭。在远程端,连接在发送消息后关闭。

我想消除设置和通过缓存打开的套接字文件描述符拆除连接的开销。在发件人方面,这很容易 - 我只是不关闭连接,并保持它们。

在接收端,这有点困难。我知道我可以将accept()返回的FD存储在一个结构中,并使用poll()select()监听所有此类套接字上的消息,但我想同时通过accept()监听所有缓存连接的新连接。

如果我使用两个线程,一个在poll(),一个在accept(),那么当accept()调用返回(一个新的连接被打开),我要唤醒其他线程等待旧的连接集。我知道我可以用信号和pselect()来做到这一点,但是对于一些如此简单的事情来说,这种混乱看起来像是太多的工作。

是否有电话或优越的方法,可以让我同时处理被打开新的连接和旧的连接发送的数据?

回答

23

我最后一次检查,你可能只是一个插座上listen,然后selectpoll,看是否有连接进来如果是这样,它accept。它不会阻止(但你 可能要 真的应该集O_NONBLOCK只是要确定)

+9

嗯,这是一个众所周知的竞争条件 - 在'接受(2)如果客户端下降的两次系统调用之间的连接尝试'将阻止。你*需要*监听套接字是非阻塞的。 – 2010-08-10 00:35:25

+6

这是正确的 - 你可以在你的'select()'调用中将你的监听文件描述符添加到'readfds'中,如果文件描述符有连接准备好,''接受()'。 @Nikolai也是正确的 - 监听套接字应该是非阻塞的并且'accept()'调用准备处理'EAGAIN'。 – caf 2010-08-10 00:35:36

0

我把在单独的进程(线程)的监听器不能把事情搞得一团糟。并且在另一个上运行一个工作进程来处理现有的套接字。真的不需要非阻塞侦听器。并且没有线程开销运行2个线程。

它应该这样:你对你的监听线程接受,直到它会返回客户端套接字的描述符,并把它传递给工人这是做所有脏读/写的工作就可以了。

如果你要听多个端口,不想持有每听者,我建议一个过程,你设置你的插座O_NONBLOCK和做点事,如:

// loop through listeners here and poll'em for read, when read is successful call accept, get descriptor, pass it to worker and continue listen 
    while(1){ 
     foreach(serverSocket in ServerSockets){ 
      if(serverSocket.Poll(10, SelectRead)){ 
        clientSocket = serverSocket.Accept(); 
        // pass to worker here and release 
      } 

     } 
    } 
+0

你在那里纺纱,不好。每个套接字一个线程的方式太多了。 – Borealid 2010-08-11 14:13:11

+0

这个纺纱有什么不好? :)它不会吃任何CPU,除此之外它允许你在一个线程中监听多个端口。 – hoodoos 2010-08-23 12:22:03

+0

这很糟糕,你正忙着等待每个监听套接字上的10usec超时,这样会吃掉CPU。最好在所有监听套接字上同时使用'select',它会阻塞,直到至少有一个连接有传入,然后尝试从每个套接字中“接受”(确保,被标记为'O_NONBLOCK',并为'accept'准备好为那些没有连接的套接字返回'EAGAIN'或'EWOULDBLOCK')。 – 2012-06-28 00:50:33

5

你可以使用听,然后使用或选择然后调查接受

if (listen (socket_fd, Number_connection) <0) 
{ 
    perror("listen"); 
    return 1; 
} 
fd_set set; 
struct timeval timeout; 
int rv; 
FD_ZERO(&set); /* clear the set */ 
FD_SET(socket_fd, &set); /* add our file descriptor to the set */ 

timeout.tv_sec = 20; 
timeout.tv_usec = 0; 

rv = select(socket_fd + 1, &set, NULL, NULL, &timeout); 
if(rv == -1) 
{ 
    perror("select"); /* an error accured */ 
    return 1; 
} 
else if(rv == 0) 
{ 
    printf("timeout occurred (20 second) \n"); /* a timeout occured */ 
    return 1; 
} 
else 
    client_socket_fd = accept (socket_fd,(struct sockaddr *) &client_name, &client_name_len); 
+0

如果fd_set还有数据可能要读取且不在监听的fds,该怎么办? – Abhishek 2014-04-09 07:11:12

相关问题