【问题标题】:Multi threaded client server多线程客户端服务器
【发布时间】:2011-04-28 09:50:46
【问题描述】:

您好,我正在编写多线程客户端服务器的作业。 到目前为止,我所做的是在端口中打开一个套接字并分叉两个线程来监听和写入客户端。但是我需要将两种类型的客户端连接到服务器并以不同的方式为它们提供服务。我的问题是我最好的方法是什么?

我在一个有无限循环接受连接的类中处理连接。当一个连接被接受时,该类创建两个线程来读取和写入客户端?现在如果我想处理另一个不同类型的客户,我们应该怎么做?

我需要打开另一个端口吗?或者是否可以通过同一个端口提供服务?可能是如果可以识别套接字中的客户端类型而不是我可以不同地处理消息。

或者你有这样的建议吗?

  1. 为两种类型的客户端分叉两个线程,并在不同端口的每个线程中监控入站连接。
  2. 当一个连接接受时,每个线程都会产生另外两个用于监听和写入的线程。

请提出建议。

【问题讨论】:

    标签: c++ multithreading sockets unix tcp


    【解决方案1】:

    不同的协议通常在不同的端口上提供服务。但是,您可以通过协商要使用的协议在同一端口上为两种类型的客户端提供服务。这可以像客户端发送HELOEHLO 以请求一种或另一种服务一样简单。

    【讨论】:

      【解决方案2】:

      也许你会从 Unix 用户那里得到更好的答案,但我会提供我所知道的。

      您的服务器需要一个线程来打开等待传入连接的“侦听”套接字。为简单起见,该线程可以是主线程,但如果您关心 UI 交互,则可以作为备用线程(在 Windows 中,这将是一个问题,不确定 Unix)。听起来你至少到此为止。

      当“侦听”套接字接受连接时,您将获得一个连接到“客户端”套接字的“已连接”套接字。您可以将此“已连接”套接字传递给一个新线程,该线程管理从 读取和 写入“已连接”套接字。因此,我建议的一项更改是在单个线程中管理“已连接”套接字,而不是像您所做的那样管理两个单独的线程(一个用于读取,一个用于写入)。可以使用select() 系统调用来完成对同一个套接字的读取和写入,如here 所示。

      当新客户端连接时,您的“监听”套接字将提供一个新的“已连接”套接字,您会将其移交给另一个线程。此时,您有两个线程——一个管理第一个连接,一个管理第二个连接。就套接字而言,客户端之间没有区别。您只需有两个打开的连接,一个连接到您的两个客户端。

      此时,问题变成了“以不同方式为他们服务”意味着什么。如果期望客户端以独特的方式与服务器交互,那么这必须以某种方式确定。可以根据“客户端”套接字的 IP 地址确定交互,您可以查询该地址,但这似乎是任意的,并且受网络变化的影响。它还可以基于从“客户端”套接字接收到的初始数据块,该数据块指示所需的交互类型。在这种情况下,管理“已连接”套接字的线程可以读取套接字以获得预期的交互类型,然后将套接字交给管理该交互类型的类对象。

      我希望这会有所帮助。

      【讨论】:

        【解决方案3】:

        您可以在一个线程中处理单个客户端连接上的读写。基于多线程的最简单的解决方案是这样的:

        // C++ like pseudo-code
        while (server_running)
        {
            client = server.accept();
            ClientHandlingThread* cth = CreateNewClientHandlingThread(client);
            cth->start();
        }
        
        class ClientHandlingThread
        {
            void start()
            {
                 std::string header = client->read_protocol_header();
                 // We get a specific implementation of the ProtocolHandler abstract class
                 // from a factory, which create objects by inspecting some protocol header info. 
                 ProtocolHandler* handler = ProtocolHandlerFactory.create(header);         
                 if (handler)
                     handler->read_write(client);
                 else
                    log("unknown protocol")
            }    
        };
        

        为了更好地扩展,您可以使用线程池,而不是为每个客户端生成一个新线程。有很多free thread pool实现for C++

        while (server_running)
        {
            client = server.accept();
            thread_pool->submit(client);
            cth->start();
        }
        

        可以通过使用一些实现reactor pattern 的框架来进一步改进服务器。他们在后台使用selectpoll 函数。您可以直接使用这些功能。但对于生产系统,最好使用现有的反应器框架。 ACE 是最广为人知的 C++ 工具包之一,用于开发高度可扩展的并发应用程序。

        【讨论】:

          猜你喜欢
          • 2014-12-21
          • 1970-01-01
          • 1970-01-01
          • 2017-10-10
          • 2019-05-17
          • 2015-01-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多