C++ C++;带有recv/send命令的服务器&;请求/响应设计

C++ C++;带有recv/send命令的服务器&;请求/响应设计,c++,server,send,recv,winsockets,C++,Server,Send,Recv,Winsockets,我试图创建一个带有阻塞套接字的服务器(每个新客户机一个新线程)。该线程应该能够从客户端接收命令(并发回结果),定期向客户端发送命令(并请求发回结果) 我的想法是为每个客户端创建两个线程,一个用于recv,第二个用于send。然而: 这是正常线程开销的两倍 由于请求/响应设计,我在第一个线程中执行的recv(等待客户端命令)可以是我在第二个线程中查找的请求(客户端的结果发送给我),反之亦然。要使所有这些都正确地同步,可能是一件糟糕的事情。现在我想从一个线程这样做: 在循环中: setsockopt

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

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

  • 这是正常线程开销的两倍
  • 由于请求/响应设计,我在第一个线程中执行的recv(等待客户端命令)可以是我在第二个线程中查找的请求(客户端的结果发送给我),反之亦然。要使所有这些都正确地同步,可能是一件糟糕的事情。现在我想从一个线程这样做:
  • 在循环中:

  • setsockopt(SO_RCVTIMEO和small_timeout)//设置recv的超时时间(如1000毫秒)
  • recv()//首先检查客户端的请求。如果返回WSAETIMEDOUT,则我假设没有请求任何数据,并且不执行任何操作。如果我收到一个正常的请求,我会处理它
  • if(clientbufferToSend!=nullptr)send(clientbufferToSend)//现在,当处理完客户机的请求后,我们将检查必须发送给客户机的命令列表。如果队列中有命令,我们将发送它们。所以可以将\u SNDTIMEO timeout设置为一个较大的值,以便在客户端断开连接时不会死锁。
    
  • setsockopt(SO_RCVTIMEO和large_timeout)//设置recv的超时时间(与SO\u SNDTIMEO一样大,只要不死锁即可)

  • recv()//现在我们等待客户端的响应

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


    p.S.
    recv()
    是否只有在没有可用数据时才返回超时值
    WSAETIMEDOUT
    ?如果有数据,它是否可以返回此错误,但
    recv()
    的速度不够快,无法处理所有数据,因此会返回部分数据?

    一种方法是只创建一个后台线程以从该套接字读取数据。在任何引发未经请求事件的随机线程上写入

    你需要以下材料

  • 每个套接字的一个关键部分或互斥锁,用于序列化写操作,例如后台线程向客户机启动的消息发送响应,而其他线程希望向同一客户机发送消息

  • 其他一些同步原语,如条件变量,用于客户端线程在等待响应时休眠

  • 接收消息的后台线程需要区分客户端启动的消息(需要由同一后台线程响应)和服务器启动的消息的响应。如果您的网络协议没有这些数据,您必须更改协议

  • 如果您的服务器启动的事件仅发生在单个线程上,例如,它们来自某个序列化源(如设备或操作系统接口),则这将正常工作


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

    使用超时阻塞I/O速度不必要地慢——如果您想要获得良好的性能,我建议使用非阻塞套接字,并对传出数据进行自己的排队,对传入数据进行缓冲。如果您的程序设计为只在
    select()
    (或
    poll()
    或类似内容)内运行,则只需一个线程即可实现高效的低延迟/全双工通信。@JeremyFriesner谢谢,我将尝试一下。