1

我开发了一个服务器/多个客户端 TCP 应用程序。

客户端由 x 个线程组成,每个线程对自己的数据进行处理,然后通过 TCP 套接字将数据发送到服务器进行显示。

服务器基本上是一个有窗口的 GUI。服务器从客户端接收数据并显示它。

现在,问题是由于客户端内部有 40 个线程并且每个线程都想发送数据,我如何使用一个连接的套接字来实现呢?

我的建议:

我的方法是在 40 个线程中的每个线程中创建一个数据结构,在其中维护要发送的数据。然后创建一个单独的发送线程,在客户端有一个连接的套接字。该线程将从第一个线程的数据结构中读取数据,通过套接字发送数据,然后从第二个线程读取数据,依此类推。

困惑:

但我不确定这将如何实施,因为我对这一切都不熟悉?:( 如果一个线程正在写入数据结构并且发送线程尝试同时读取数据怎么办。我熟悉互斥锁、临界区等,但这对于我的简单应用程序来说听起来太复杂了。

除了我自己的建议之外的任何其他建议/评论都是受欢迎的。如果您认为我自己的方法是正确的,那么请帮助我解决我上面提到的困惑。

提前非常感谢:)

编辑:

我可以将定时器放在发送线程上,并在特定时间后发送线程挂起线程#1(以便它可以访问其数据结构而不会出现任何同步问题),从其数据结构中读取数据,通过 tcp 套接字发送数据,然后恢复 Thread#1,然后暂停 Thread#2,从其数据结构中读取数据,通过 tcp Socket 发送数据,然后恢复 Thread#2,依此类推。

4

3 回答 3

1

一种常见的方法是让一个线程专用于发送数据。其他线程将它们的数据发布到共享容器(列表、双端队列等)中,并向发送者线程发出数据可用的信号。然后发送者醒来并处理任何可用的数据。

编辑:

它的要点如下:

HANDLE data_available_event; // manual reset event; set when queue has data, clear when queue is empty
CRITICAL_SECTION cs; // protect access to data queue
std::deque<std::string> data_to_send;

WorkerThread()
{
    while(do_work)
    {
        std::string data = generate_data()
        EnterCriticalSection(&cs);
        data_to_send.push_back(data);
        SetEvent(data_available_event); // signal sender thread that data is available
        LeaveCriticalSection(&cs);
    }
}

SenderThread()
{
    while(do_work)
    {
        WaitForSingleObject(data_available_event);
        EnterCriticalSection(&cs);
        std::string data = data_to_send.front();
        data_to_send.pop_front();
        if(data_to_send.empty())
        {
            ResetEvent(data_available_event); // queue is empty; reset event and wait until more data is available
        }
        LeaveCriticalSection(&cs);
        send_data(data);
    }
}

这当然是假设数据可以按任何顺序发送。我仅出于说明目的使用字符串;您可能想要某种知道如何序列化它所拥有的数据的自定义对象。

于 2013-05-30T11:25:29.863 回答
1

暂停线程#1 以便您可以访问其数据结构并不能避免同步问题。当您挂起它时,线程#1 可能正在更新数据,因此套接字线程获取旧数据的一部分,新数据的一部分。那就是数据损坏。

您需要一个共享数据结构,例如 FIFO 队列。工作线程添加到队列中,套接字线程从队列中删除最旧的项目。除非您实现无锁队列,否则对这个共享队列的所有访问都必须使用临界区进行保护。(一个循环缓冲区。)

根据您的应用程序需要,如果您实现此队列,您可能根本不需要套接字线程。只需在显示线程中进行出队即可。

于 2013-05-30T14:32:39.893 回答
0

有几种方法可以实现它;卢克的想法受到仍然会造成数据损坏的竞争条件的影响

您可以通过使用 UDP 而不是 TCP 作为传输协议来避免这种情况。如果您不介意偶尔丢失一个数据包(这对于显示快速变化的数据来说是可以的),这将是一个特别好的选择;在准确的历史记录无关紧要的情况下,确保实时更新数据非常棒(在绘制图形时错过相对平滑的曲线中的一点是可以的);

如果数据包很小并且有点代表流,那么 UDP 是一个不错的选择。如果您在不同系统上的多个发件人都显示在一个屏幕上,它的好处就会增加。

于 2013-05-30T11:41:39.627 回答