c++tcp多线程客户端/服务器-如何与线程套接字处理程序进行通信



我用c++制作了一个多线程客户端/服务器。它运行良好。"协议"是基于文本的。我有一个sockethandler函数(它以无限循环的方式运行,直到连接出现问题或客户端正常断开连接),在线程启动后,服务器正在等待新的连接。现在,对于这个特定的程序,我一次只允许一个客户端。到目前为止,客户端一直是启动器,服务器会做出响应。但我需要从其他线程向客户端程序发送大量数据(而不是大小、频率),我不知道如何发送。我的代码是跨平台的——我从同一个源为windows和linux编译。客户端/服务器代码是跨平台的,也有几行。。。最好的方法是什么?队列?还是有更快的方法?有人能给我指正确的方向吗?或者给我一些示例代码?我确实试着把它整理好,并在设计上明智地考虑在客户端添加一个udp侦听器,在服务器添加一个udp发送器,这样我就有了两个通信渠道,但我不知道这是否是一个好的做法。。。我目前在线程中有一个套接字,但我只知道如何从一个方向使用它——这是我的主要问题。。。

在设计方面,我正在考虑为客户端添加一个udp侦听器一个udp发送器到服务器,这样我就有2个通信通道但我不知道这是不是一个好的做法。。。

你可能会遇到的主要问题(除了通常涉及丢弃数据包的UDP问题之外)是,客户端机器通常会运行防火墙来阻止所有传入的UDP数据包。如果是这种情况,你需要指示用户禁用防火墙或向防火墙添加规则,以允许在你使用的端口上传入UDP数据包(这可能是一个合理的请求,也可能不是,取决于你的用户是谁,但肯定会很麻烦)。

考虑到这一点,如果你能像往常一样让客户端通过TCP连接到服务器,并通过你已经使用的相同TCP连接将客户端需要的数据发送回客户端,那可能会更好。这样可以避免防火墙问题。

客户端/服务器代码跨平台太多了线最好的方法是什么?队列?或者有更快的方法?有人能给我指正确的方向吗请给我一些示例代码?

由于你在评论中指出你的主要问题是跨线程通信,下面是我在多线程程序中处理这个问题的方法:

  1. 我的每个线程都使用非阻塞I/O和以阻塞调用select()为中心的事件循环。其思想是,线程应该阻塞的唯一位置是select()调用,并且select()只应在线程还有更多工作要做时返回。

  2. 为了让线程A向线程B发送消息,线程A必须执行以下操作:

    a。锁定保护线程B的传入消息队列的互斥对象b.将消息附加到线程b的传入消息队列的末尾c.解锁保护线程B传入消息队列的互斥对象d.给线程B发信号,使线程B醒来并检查其传入消息队列中的新消息

  3. 除了(d)部分——让线程B可靠地唤醒之外,以上所有内容都很简单。为了做到这一点,我(在启动时)创建了一个管道或套接字对,线程a可以发送到它,线程B可以在上面选择()。因此,作为(d)的一部分,线程a向管道(或套接字对)末端的套接字写入一个字节,这会导致线程B的套接字选择()作为读取准备。当线程B看到这一点时,它从套接字中读取字节(当然是非阻塞读取),将其丢弃,然后锁定其传入的消息队列,从该队列中获取所有消息,再次解锁,然后按顺序处理获取的消息。

请注意,为了保持效率,您可能希望使Message对象尽可能为零拷贝,尤其是在它们将包含大量数据的情况下。您可以使用shared_ptr或类似的方法来实现这一点,这样您添加到队列中的只有相对较小的shared_ptr对象,而不是它们指向的较大的Message/数据。使用智能指针还可以确保Message/数据不会泄露内存。

这类事情可能也适用于阻塞I/O,只是如果你使用阻塞I/O,你就无法保证线程需要多长时间来响应你发送的消息——特别是如果存在网络问题,那么线程在TCP套接字上对send()的调用可能在几分钟内不会返回,对此你无能为力——当然,如果没有来自客户端的数据,对recv()的调用可能会永远阻塞。这就是为什么如果可能的话,我总是使用非阻塞I/O。

当客户端连接到服务器时,我假设在服务器中有一个进出文件。因此,如果您只需要一个可从服务器中的各种任务访问的客户端共享通信通道,那么您应该有一个接收通信并打开通信通道的任务(进行内务管理)。之后,您可以通过使用锁将"共享资源"用作每个线程的全局变量,以防止损坏。

最新更新