TCP服务器架构

TCP Server architecture

本文关键字:服务器 TCP      更新时间:2023-10-16

我正在c++中构建一个TCP服务器,这是多线程的,每个客户端都有自己的线程,我有一个问题,我希望有人能回答我。我知道这类问题没有灵丹妙药,可能会有多种方法来处理它,我主要是在寻找对我的想法的反馈,让我自己更清楚地了解情况,以及如何管理它。

我现在的基本设置是这样的…

  1. 类A监听传入连接
  2. 当建立连接时,它实例化一个新类(类B)并为它生成一个新线程
  3. 类A返回监听传入的连接,而类B管理一个特定的连接。

我想知道从架构的角度来看,向客户端发送消息和从客户端发送消息的最佳方式是什么。

我最初的想法是将所有客户端的引用传递给每个客户端线程,然后每个客户端线程都有一个"SendTo"函数,然后可以向该特定用户发送消息。

但是经过一段时间的思考,我开始想知道"将所有客户端的参考传递给每个线程会是一个好的设计吗?"我真的不确定,我想这就是我在这里的原因!

无论如何,所以我开始考虑有一个"SendTo"回调函数到a类,它将从B类线程传递到/从ID,试图发送消息。如果我这样做,我认为我需要一个互斥锁在这个函数的顶部,因为它将是一个共享资源,对吗?但在那之后,我开始思考:"如果有很多消息来回传递,而且它们都必须经过同一个功能,那岂不是效率低下、速度缓慢?"

所以我只是有点困惑,最好的设计方法是什么,可能有一个更好的方法来处理这个问题,我甚至不知道这是我想写这篇文章的另一个原因。

在这两种情况下,你都无法避免对竞态条件的保护:

首先,需要一些数据结构来存储到目前为止存在的所有连接。然后,还有套接字本身。

我建议使用两级锁:

如果并发地读取公共数据结构没有问题,但是如果A线程在任何B线程读取它的时候修改它,你就会陷入大麻烦。查看一下共享互斥锁,这正是您需要的……

任何一个套接字只能被独占地访问。因此,为每个互斥对象提供一个普通的单访问互斥对象。最后得到的结果是:

A、新客户:

  • 创建一个新的套接字
  • 获取socket列表互斥锁,独占锁
  • 在数据结构中插入新的套接字
  • <
  • 释放锁/gh>

B,发送共同信息:

  • 获取socket列表互斥锁,共享锁
  • 遍历套接字列表,为每个套接字:
    • 获取套接字互斥锁,独占锁(只有一个可用…)
    • 写消息到套接字
    • 释放socket的互斥锁
  • 释放套接字列表互斥

这最小化了任何排他锁实际需要持有的时间(当然,socket和socket的互斥锁是由类B管理的)。

它只是一个见过的味道,如果你实现这个类B接收数据结构的引用和共享互斥锁(preferrably然后,然而,一个单独的类包含并提供一个一致的接口)或者如果你简单地提供一个回调(或参考类),被称为任何B前提供了更好的可重用性(特别是如果你实现这个新类作为模板),后者更好的分离(B关心一个客户,仅此而已),并且可能需要更少的代码(没有单独的类;但是,您仍然可以实现这样的可重用性)。

我假设我们谈论的是聊天风格的应用程序,客户端可以相互发送消息。可以是私人消息、组消息或广播消息。重要的是这些消息是异步发生的,即一个客户端发送的消息完全独立于另一个客户端发生的任何事情。

有一个专门的对象来处理这类事件是合理的。除了主要的事件类型,"客户端发送消息给其他(s)",它可以处理其他事件:"客户端连接/断开连接","客户端加入/离开组"等。客户端处理程序可以订阅这些事件。

可以设想一个具有许多事件队列的系统:一个队列用于每个客户端的私有消息,一个组队列用于每个客户端组,一个广播队列用于服务所有客户端。每个客户端处理程序根据需要订阅或多或少。

当处理程序通过TCP从客户端接收消息时,它只是将其推送到适当的队列(可能有许多副本,每个收件人一个);或者让一个单独的队列管理器线程根据需要复制消息)。

可以使队列无锁(例如boost),这意味着没有人阻塞其他任何人。