多线程和多个TCP连接

时间:2013-01-23 21:06:04

标签: linux sockets tcp pthreads

我有一个有多个线程的应用程序,一个线程正在创建4个tcp连接,然后这个线程创建另一个线程,它将使用poll或其他任何东西处理这4个连接的接收函数,以及原始线程(第一个)开始向这4个连接发送消息(循环)。它就像伪代码一样,

main()
{

    pthread_create( &thread1, NULL, sending_thread, (void*) args);

}

void *sending_thread( void *ptr )
{
    int i=0;
    int *connections;
    connections = create_connections();

    pthread_create( &thread1, NULL, receiving_thread, (void*)&connections);
        while(1) {

        send(connections[i], "test"); 
        i++;
        if (i > 3)
        i=0;             

        }
}

void *receiving_thread( void *ptr )
{
    char *msg; 
        msg = receive(connections[i]);
        save_received_msg_to_disk(msg);

}

我的问题是如何检查我的连接并启动断开的连接?例如,假设connection1关闭,我是否需要使用相同的fd创建另一个连接,在这种情况下是连接[1]?还是有其他方法来处理这种情况?

Linux中的环境是C / pthread

1 个答案:

答案 0 :(得分:1)

以下是基于您的代码和评论的一些要点。

  • 虽然线程确实允许并行发生某些事情,但就更复杂的设计而言,它们通常具有非零成本,这总是归结为同步。就像你的情况一样,没有简单的方法可以重新建立其中一个连接并再次在两个线程之间共享它。
  • 我从未见过输入和输出流完全独立的应用。我可以想象像隧道代理或基于TCP的VPN这样的东西可能有意义,但一般情况下,一些更高级别的协议仍然会强加一些请求 - 响应语义,这些语义再次强加/要求在发送和接收线程之间进行仲裁。
  • 当您需要吞吐量并尝试最小化延迟时,情况会有所不同。对于前者来说,在互斥上等待睡眠通常是可以的,但对后者来说很少是个好主意。从单个线程循环写入几个阻塞套接字会伤害它们。
  • 如果您有大量输出流和稀疏输入,那么使用epoll(7)之类的东西来检测饱和连接,并在它们再次可用时通知然后让其他人饿死是有意义的。

我知道这不会直接回答你的问题,但我的 rant 列表不符合评论。希望这有点帮助。

编辑0:

以下是epoll(7)的常用设置:

  • 使您的套接字无阻塞(fcntl(2)O_NONBLOCK)。
  • epoll_data.fd设置为每个潜在通道的套接字描述符(示例中为四个套接字)。如果你想保留更复杂的结构,那么union epoll_data可以使用其他选项。
  • 使用EPOLLINEPOLLET获取边缘触发的行为,即在输入缓冲区变空时唤醒。
  • 如果您从EPOLLOUT获得EWOULDBLOCK,则只设置write(2),否则请照常输出。与EPOLLET相同的逻辑用于检测输出缓冲区空间是否可用。
  • 使用EPOLLRDHUP检测其他方面是否干净地断开连接(对于突然断开连接,您需要处理EPIPE错误格式write(2)。)
  • epoll_wait(2)为您提供要迭代的事件数量。对输入(events & EPOLLIN)和输出(events & EPOLLOUT)进行单独检查。
  • data.fd(或其他关联的套接字)读取的输入,直到您获得EWOULDBLOCK
  • 在输出写入之前,直到获得EWOULDBLOCK或者您没有更多的输出数据待处理(在这种情况下删除EPOLLOUT)。

它看起来很多,但是一旦你掌握它就很简单。

你也可以做非阻塞connect(2),如果你想重新建立破碎的流而不会伤害仍在继续的其他人(connect(2)返回{{1},这可能是一个好主意。将errno(3)设置为-1,并等待套接字变为可写,如上所述。)