同时使用accept()和select()?

时间:2010-08-09 22:39:44

标签: sockets tcp network-programming

我有一个事件驱动的网络服务器程序。此程序接受来自其他主机上其他进程的连接。来自同一远程IP的不同端口可能存在许多短期连接。

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

我希望通过缓存打开的套接字FD来消除设置和拆除连接的开销。在发送方,这很容易 - 我只是不关闭连接,并保持它们。

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

如果我使用两个线程,一个在select()上,另一个在accept()上,那么当poll()调用返回(打开一个新连接)时,我必须唤醒另一个线程在旧的连接集上等待。我知道我可以通过信号和accept()来做到这一点,但是对于这么简单的事情来说,整个混乱似乎太过分了。

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

3 个答案:

答案 0 :(得分:23)

我上次检查时,你可以在套接字上listen,然后selectpoll查看是否有连接。如果是,accept它;它不会阻止(但你可能想要 真的设置O_NONBLOCK只是为了确定)

答案 1 :(得分:5)

你可以使用listen然后使用select或poll然后接受

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);

答案 2 :(得分:0)

我将一个监听器放在一个单独的进程(线程)中,不要搞砸了。并在另一个上运行一个工作进程来处理现有的套接字。真的不需要非阻塞侦听器。没有线程开销运行2个线程。

它应该是这样的:你接受你的监听器线程,直到它返回一个客户端套接字的描述符,并将它传递给正在对其进行所有脏读/写工作的worker。

如果你想要监听多个端口并且不希望每个监听器保持一个进程,我建议你在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
             }

        }
    }