c++ tcp multithreaded client/server - 如何与线程 sockethandler 通信?
c++ tcp multithreaded client/server - how to communicate with threaded sockethandler?
我用c++做了一个多线程client/server。它工作正常。 'protocol' 是基于文本的。我有一个 sockethandler 函数(在无限循环中运行线程,直到连接发生某些事情或客户端优雅地断开连接)在该线程启动后服务器正在等待新连接。现在,对于这个特定的程序,我一次只允许一个客户。到目前为止,客户端一直是发起者,服务器响应。但我需要从其他线程向客户端程序发送大量数据(不是大小、频率),但我不知道该怎么做。我的代码是跨平台的——我从同一来源编译 windows 和 linux。 client/server 代码也是跨平台的,请多加几行...最好的方法是什么?队列?还是有更快的方法?有人可以指出我正确的方向或给我一些示例代码吗?
我确实尝试将其整理出来并在设计方面考虑我正在考虑向客户端添加一个 udp 侦听器,向服务器添加一个 udp 发送器,以便我有 2 个通信通道,但我不知道这是否是一个好习惯......
我目前在线程中有一个套接字,但我只知道如何从一个方向使用它 - 这是我的主要问题...
当客户端连接到服务器时,我想在服务器中您有一个输入和输出文件。因此,如果您只需要一个与您的客户端可从服务器中的各种任务访问的共享通信通道,您应该有一个接收通信并打开通信通道的任务(做内务处理)。之后,您可以通过使用锁来将 "shared resource" 作为每个线程的全局变量来使用,以防止损坏。
design-wise I'm considering adding an udp listener to the client and
an udp sender to the server so that I have 2 communication channels
but I don't know if that a good practice...
您可能 运行 遇到的主要问题(除了涉及丢包的常见 UDP 问题之外)是客户端计算机通常 运行 设置了一个防火墙来阻止所有传入的 UDP 数据包。如果是这种情况,您需要指示用户禁用防火墙或向防火墙添加规则以允许在您使用的端口上传入 UDP 数据包(这可能是也可能不是合理的请求,具体取决于您的用户)用户是,但肯定会很麻烦)。
鉴于此,如果您能让客户端像往常一样通过 TCP 连接到服务器,并通过您已经在使用的同一 TCP 连接将客户端需要的数据发送回客户端,可能会更好.这样就避免了防火墙问题。
The client/server code is cross platform too give or take a few
lines... What's the best method to do this? queues? or are there
faster methods? can someone point me in the right direction or give me
some example code please?
由于您在评论中指出您的主要问题是跨线程通信,因此这是我在多线程程序中处理该问题的方式:
我的每个线程都使用非阻塞 I/O 和一个以阻塞调用 select() 为中心的事件循环。这个想法是线程唯一应该阻塞的地方是 select() 调用,并且 select() 调用应该 return 只有当线程有更多工作时去做。
为了让线程 A 向线程 B 发送消息,线程 A 必须执行以下操作:
一个。锁定保护线程 B 的传入消息队列的互斥锁
b.将消息附加到线程 B 的传入消息队列的末尾
C。解锁保护线程 B 的传入消息队列的互斥锁
d.向线程 B 发出信号,以便线程 B 唤醒并检查其传入消息队列中是否有新消息
除了 (d) 部分之外,以上所有内容都很简单——让线程 B 可靠地唤醒。为此,我创建了(在启动时)线程 A 可以发送到的 pipe or socket-pair 并且线程 B 可以 select() on。因此,作为 (d) 的一部分,线程 A 将一个字节写入其管道末端的套接字(或套接字对),这会导致线程 B 的套接字变为 select() 准备好读取。当线程 B 看到时,它从套接字中读取字节(当然是非阻塞读取),将它们扔掉,然后锁定其传入消息队列,从该队列中取出所有消息,再次解锁,然后按顺序处理抓取的Messages。
请注意,为了保持效率,您可能希望使 Message 对象尽可能零拷贝,尤其是当它们将包含大量数据时。您可以使用 shared_ptr 或类似的方法来做到这一点,这样您添加到队列中的唯一东西就是相对较小的 shared_ptr 对象,而不是它们指向的较大的 Message/data 对象。使用智能指针还可以确保 Messages/data 不会发生内存泄漏。
这种事情也可能与阻塞 I/O 一起工作,除了如果你使用阻塞 I/O 你将无法保证线程响应一个线程需要多长时间您发送的消息——特别是如果存在网络问题,则线程对 TCP 套接字上的 send() 的调用可能不会 return 好几分钟,而且您对此无能为力——并且当然,如果没有来自客户端的数据,对 recv() 的调用可能会永远阻塞。这就是为什么我总是尽可能使用非阻塞 I/O。
我用c++做了一个多线程client/server。它工作正常。 'protocol' 是基于文本的。我有一个 sockethandler 函数(在无限循环中运行线程,直到连接发生某些事情或客户端优雅地断开连接)在该线程启动后服务器正在等待新连接。现在,对于这个特定的程序,我一次只允许一个客户。到目前为止,客户端一直是发起者,服务器响应。但我需要从其他线程向客户端程序发送大量数据(不是大小、频率),但我不知道该怎么做。我的代码是跨平台的——我从同一来源编译 windows 和 linux。 client/server 代码也是跨平台的,请多加几行...最好的方法是什么?队列?还是有更快的方法?有人可以指出我正确的方向或给我一些示例代码吗? 我确实尝试将其整理出来并在设计方面考虑我正在考虑向客户端添加一个 udp 侦听器,向服务器添加一个 udp 发送器,以便我有 2 个通信通道,但我不知道这是否是一个好习惯...... 我目前在线程中有一个套接字,但我只知道如何从一个方向使用它 - 这是我的主要问题...
当客户端连接到服务器时,我想在服务器中您有一个输入和输出文件。因此,如果您只需要一个与您的客户端可从服务器中的各种任务访问的共享通信通道,您应该有一个接收通信并打开通信通道的任务(做内务处理)。之后,您可以通过使用锁来将 "shared resource" 作为每个线程的全局变量来使用,以防止损坏。
design-wise I'm considering adding an udp listener to the client and an udp sender to the server so that I have 2 communication channels but I don't know if that a good practice...
您可能 运行 遇到的主要问题(除了涉及丢包的常见 UDP 问题之外)是客户端计算机通常 运行 设置了一个防火墙来阻止所有传入的 UDP 数据包。如果是这种情况,您需要指示用户禁用防火墙或向防火墙添加规则以允许在您使用的端口上传入 UDP 数据包(这可能是也可能不是合理的请求,具体取决于您的用户)用户是,但肯定会很麻烦)。
鉴于此,如果您能让客户端像往常一样通过 TCP 连接到服务器,并通过您已经在使用的同一 TCP 连接将客户端需要的数据发送回客户端,可能会更好.这样就避免了防火墙问题。
The client/server code is cross platform too give or take a few lines... What's the best method to do this? queues? or are there faster methods? can someone point me in the right direction or give me some example code please?
由于您在评论中指出您的主要问题是跨线程通信,因此这是我在多线程程序中处理该问题的方式:
我的每个线程都使用非阻塞 I/O 和一个以阻塞调用 select() 为中心的事件循环。这个想法是线程唯一应该阻塞的地方是 select() 调用,并且 select() 调用应该 return 只有当线程有更多工作时去做。
为了让线程 A 向线程 B 发送消息,线程 A 必须执行以下操作:
一个。锁定保护线程 B 的传入消息队列的互斥锁 b.将消息附加到线程 B 的传入消息队列的末尾 C。解锁保护线程 B 的传入消息队列的互斥锁 d.向线程 B 发出信号,以便线程 B 唤醒并检查其传入消息队列中是否有新消息
除了 (d) 部分之外,以上所有内容都很简单——让线程 B 可靠地唤醒。为此,我创建了(在启动时)线程 A 可以发送到的 pipe or socket-pair 并且线程 B 可以 select() on。因此,作为 (d) 的一部分,线程 A 将一个字节写入其管道末端的套接字(或套接字对),这会导致线程 B 的套接字变为 select() 准备好读取。当线程 B 看到时,它从套接字中读取字节(当然是非阻塞读取),将它们扔掉,然后锁定其传入消息队列,从该队列中取出所有消息,再次解锁,然后按顺序处理抓取的Messages。
请注意,为了保持效率,您可能希望使 Message 对象尽可能零拷贝,尤其是当它们将包含大量数据时。您可以使用 shared_ptr 或类似的方法来做到这一点,这样您添加到队列中的唯一东西就是相对较小的 shared_ptr 对象,而不是它们指向的较大的 Message/data 对象。使用智能指针还可以确保 Messages/data 不会发生内存泄漏。
这种事情也可能与阻塞 I/O 一起工作,除了如果你使用阻塞 I/O 你将无法保证线程响应一个线程需要多长时间您发送的消息——特别是如果存在网络问题,则线程对 TCP 套接字上的 send() 的调用可能不会 return 好几分钟,而且您对此无能为力——并且当然,如果没有来自客户端的数据,对 recv() 的调用可能会永远阻塞。这就是为什么我总是尽可能使用非阻塞 I/O。