您好我正在编写一个编写多线程客户端服务器的作业。 到目前为止,我所做的是在一个端口中打开一个套接字并分叉两个线程来监听和写入客户端。但我需要将两种类型的客户端连接到服务器并以不同方式为它们提供服务。我的问题是什么是我最好的方法?
我在一个具有无限循环的类中处理连接以接受连接。当接受连接时,该类创建两个线程来读取和写入客户端?现在,如果我想处理另一个不同类型的客户,我们该怎么办?
我需要打开另一个端口吗?或者是否可以通过同一个港口服务?可能是因为可以识别套接字中的客户端类型而不是以不同方式处理消息。
或者你这样建议吗?
请提出建议。
答案 0 :(得分:4)
也许你会从Unix用户那里得到更好的答案,但我会提供我所知道的。
您的服务器需要一个打开“侦听”套接字的线程,该套接字等待传入连接。这个线程可以是简单的主线程,但是如果你关心UI交互,它可以是一个替代线程,例如(在Windows中,这将是一个问题,不确定Unix)。听起来你至少到目前为止。
当'listening'套接字接受连接时,你得到一个连接到'client'套接字的'connected'套接字。您可以将此“已连接”套接字传递给新线程,该线程管理从和写入“已连接”套接字的读取。因此,我建议的一个改变是在一个线程中管理'connected'套接字,而不是像你所做的那样在两个单独的线程(一个用于读取,一个用于写入)中管理。使用select()
系统调用可以完成对同一套接字的读写操作,如here所示。
当一个新客户端连接时,你的'listen'套接字将提供一个新的'connected'套接字,你将把它交给另一个线程。此时,您有两个线程 - 一个管理第一个连接,另一个管理第二个连接。就套接字而言,客户端之间没有区别。您只需要两个打开的连接,一个连接两个客户端。
此时,问题变成了“以不同方式为他们服务”意味着什么。如果希望客户端以独特的方式与服务器交互,则必须以某种方式确定。可以根据您可以查询的“客户端”套接字的IP地址来确定交互,但这似乎是任意的,并且受网络更改的影响。它还可以基于从“客户端”套接字接收的初始数据块,其指示所需的交互类型。在这种情况下,管理'connected'套接字的线程可以读取套接字以获得预期的交互类型,然后将套接字移交给管理该交互类型的类对象。
我希望这会有所帮助。
答案 1 :(得分:1)
您可以在一个线程中处理单个客户端连接上的读写。基于多线程的最简单的解决方案是:
// 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的框架,可以进一步改进服务器。他们使用select
或poll
功能。您可以直接使用这些功能。但对于生产系统,最好使用现有的反应堆框架。 ACE是用于开发高度可伸缩的并发应用程序的最广为人知的C ++工具包之一。
答案 2 :(得分:0)
通常在不同的端口上提供不同的协议。但是,您可以通过协商要使用的协议,在同一端口上为两种类型的客户端提供服务。这可以像客户端发送HELO
或EHLO
来请求一种或另一种服务一样简单。