具有 recv/send 命令和 request/response 设计的 C++ 服务器

C++ server with recv/send commands & request/response design

我正在尝试创建一个带有阻塞套接字的服务器(每个新客户端一个新线程)。该线程应该能够接收来自客户端的命令(并发回结果)并定期向客户端发送命令(并请求返回结果)。

我的想法是为每个客户端创建两个线程,一个用于 recv,第二个用于 send。然而:

  1. 它是普通线程开销的两倍。
  2. 由于 request/response 设计,我在第一个线程(等待客户端命令)中执行的 recv 可能是我在第二个线程(客户端发送的结果)中查找的请求,反之亦然。使其全部正确同步可能是一个地狱故事。所以现在我正在考虑以这种方式从单个线程执行此操作:

循环中:

  1. setsockopt(SO_RCVTIMEO, &small_timeout); // 设置接收超时(例如 1000 毫秒)。
  2. recv(); // 首先检查客户端的请求。如果 returns WSAETIMEDOUT 比我假设没有请求数据并且什么都不做。如果我收到正常请求,我会处理它。
  3. if (clientbufferToSend != nullptr) send(clientbufferToSend); // 现在当客户端的请求被处理后,我们检查我们必须发送给客户端的命令列表。如果队列中有命令,我们发送它们。 SO_SNDTIMEO 可以将超时设置为较大的值,这样我们就不会在客户端断开连接时出现死锁。
    1. setsockopt(SO_RCVTIMEO, &large_timeout); // 设置 recv 的超时时间(最大 SO_SNDTIMEO,只是为了不死锁)。

    2. recv(); // 现在我们等待客户端的响应。

这是做我想做的事情的合法方式吗?或者有更好的选择(最好是阻塞套接字和线程)?

P.S。 recv() with timeout returns WSAETIMEDOUT 只有在没有数据可用的情况下吗?如果有数据,它会 return 这个错误,但是 recv() 没有足够快地处理所有数据,因此 return 正在处理部分数据吗?

一种方法是只创建一个后台线程来从该套接字中读取数据。在任何随机线程上写下你主动提出的事件。

您需要以下内容。

  1. 每个套接字的关键部分或互斥锁用于序列化写入,例如当后台线程正在发送对客户端发起的消息的响应,而其他线程想要向同一客户端发送消息时。

  2. 一些其他同步原语,例如客户端线程在等待响应时休眠的条件变量。

  3. 接收消息的后台线程需要区分客户端发起的消息(需要由同一个后台线程响应)和服务器发起的消息的响应。如果您的网络协议没有该数据,您将不得不更改协议。

如果您的服务器启动的事件只发生在单个线程上,这将正常工作,例如它们来自一些序列化源,例如设备或 OS 接口。

但是,如果事件源也是多线程的,并且您想要良好的性能,那么您将需要非平凡的复杂性来将响应分派到正确的服务器线程,例如每个客户端线程 1 个条件变量,也许是一些队列,等等