1

我有一个具有多个线程的应用程序,一个线程正在创建 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创建另一个连接,在这种情况下是connection[1]?还是有其他方法可以处理这种情况?

环境是Linux中的C/pthread

4

1 回答 1

1

以下是基于您的代码和注释的一些要点。

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

我知道这不能直接回答你的问题,但我的咆哮列表不适合评论。希望这有所帮助。

编辑0:

这是通常的设置epoll(7)

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

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

你也可以做 non-blocking connect(2),如果你想重新建立中断的流而不伤害其他仍在运行的流,这可能是一个好主意(返回connect(2)set to并且你等待套接字变成可写的,如上)。-1errno(3)EINPROGRESS

于 2013-01-24T14:07:02.793 回答