除非您正在接收真正的高带宽流(例如每秒兆字节而不是每秒千字节),否则单线程设计就足够了。请记住,操作系统的网络堆栈始终在“后台”运行,接收 TCP 数据包并将接收到的数据存储在固定大小的内核内存缓冲区中。这与您的程序执行并行发生,因此在大多数情况下,您的程序是单线程并忙于处理 GUI 更新(或另一个套接字)这一事实不会妨碍您的计算机接收 TCP 数据包。
单线程设计会导致 TCP 流量变慢的情况是,如果您的程序(通过 Qt)没有足够快地调用 recv(),从而导致内核的套接字 TCP 接收缓冲区完全充满了数据。那时内核别无选择,只能开始丢弃该套接字的传入 TCP 数据包,这将导致服务器必须重新发送这些 TCP 数据包,这将导致套接字的 TCP 接收速度减慢,至少暂时地。但是,可以通过确保缓冲区永远不会(或至少很少)变满来避免这个问题。
显而易见的方法是确保您的程序尽可能快地读取所有传入的数据——这是 QTCPSocket 默认执行的操作。您唯一需要做的就是确保您的 GUI 更新不会花费过多的时间——并且 Qt 的小部件更新例程相当有效,所以它们不应该,除非您有一个非常精细的 GUI 或低效的自定义paintEvent() 例程等。
如果这还不够,您可以做的下一件事(如有必要)是告诉操作系统的 TCP 堆栈增加其内核 TCP 接收缓冲区的大小,例如通过执行以下操作:
int fd = myQTCPSocketObject.descriptor();
int newBufSizeBytes = 128*1024; // request 128kB kernel recv-buffer for this socket
if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &newBufSizeBytes, sizeof(newBufSizeBytes)) != 0) perror("setsockopt");
这样做会让你的(单个)线程有更多的时间在传入的数据包开始因为缺乏内核缓冲区空间而被丢弃之前做出反应。
如果在尝试了所有这些之后,您仍然没有获得所需的网络性能,那么您可以尝试使用多线程。我怀疑它会出现这种情况,但如果确实如此,它不会对你的程序设计产生太大影响;您只需编写一个包装类(称为 SocketThread 或其他东西),它包含您的 QTCPSocket 对象并运行一个处理从套接字读取的内部线程,并在线程从套接字读取数据时发出 bytesReceived(QByteArray) 信号。您的其余代码将保持大致相同;只需修改它以保存 SocketThread 对象而不是 QTCPSocket,并将 SocketThread 的 bytesReceived(QByteArray) 信号连接到相应的插槽(当然,为了线程安全,通过 QueuedConnection)并使用它而不是直接响应 readReady() .