gpt4 book ai didi

c++ - boost::asio - 服务器之间的冲突,双向通信

转载 作者:行者123 更新时间:2023-11-30 04:17:19 24 4
gpt4 key购买 nike

我正在尝试使用 ASIO 编写一个允许服务器充当客户端的应用程序。例如:

我有 3 个服务器需要相互通信。在与网络中的其他服务器通信时,它们需要能够充当客户端。所有 3 个服务器都可以通过 unix 域套接字或带有 SSL 的 TCP/IP 服务请求。

这是数据流的方式:

1) 独立客户端连接到服务器 A(通过 unix 域套接字)并向其发送请求。

2) 服务器尝试响应请求,但如果不能,它会启动到服务器 B 的 TCP/IP 连接(现在服务器 A 充当服务器 B 的客户端)并将请求转发给它。服务器还“污染”数据包以告知服务器 B 不要将消息转发到另一台服务器,这样就不会产生无限循环。

3) 服务器B如果能够处理请求,则响应服务器A。

4) 如果Server B可以处理请求,Server A返回响应给standalone client。

5) 如果服务器 B 不能处理请求,服务器 A 尝试联系服务器 C、服务器 D、服务器 E 等

这有效...直到服务器 B 拥有自己的独立客户端,在服务器 A 尝试联系服务器 B 的同时尝试联系服务器 A。它会产生冲突,并且两个服务器将无限期地等待以获得响应从另一个。使用截止时间计时器我可以避免无限期等待,但它不能解决问题。

执行此操作的正确方法是什么?

编辑:我将服务器分成 2 个类(服务器和 PeerProxy)在不同的线程中运行,但我仍然遇到死锁。

这是我所做的。我已将 Unix 监听器和 TCP 监听器拆分为类 Server 和 PeerProxy。 Server 有它自己的 io_service,PeerProxy 也有它自己的。当服务器启动时,它还会启动在第二个线程中运行的 PeerProxy(因此它不会阻止服务器的执行)。现在数据的流向是这样的:

独立客户端 -> 服务器 A(无法应答) -> PeerProxy B -> 服务器 B(得到应答) -> PeerProxy B -> 服务器 A -> 独立客户端

当服务器 B 的独立客户端在服务器 A 转到 PeerProxy B 的同时转到 PeerProxy A 时,我遇到了同样的问题。

最佳答案

您应该在服务器中异步处理每个请求,即将处理分离到单独的执行线程中。这样服务器就可以保持响应,即它们可以在与其他客户端或服务器通信时对新请求使用react。

所以在你的情况下,当两个客户端 1 和 2 向服务器 A 和 B 发送请求时,只有另一个服务器可以回答(或不回答),这两个服务器可能看起来像这样:

Server A:                                   Server B:
Thread 0 | Thread 1 | Thread 2 Thread 0 | Thread 1 | Thread 2

listen... listen...
-> req 1 -> req 2
listen... | handle req 1 listen... | handle req 2
listen... | forward to B listen... | forward to A
-> req B | wait... -> req A | wait...
listen... | wait... | handle req B listen... | wait... | reject req A
listen... | -> B: rejected | answer req B listen... | wait...
listen... | forward to C listen... | -> A: answer
listen... | -> C: answer listen... | req 2 done
listen... | req 1 done listen...
listen... listen...

在这里,每个服务器的线程 0 除了监听传入请求和处理这些请求的其他线程的旋转之外没有其他目的。其他线程通过回答请求或将其转发给所有服务器或在请求被“污染”时拒绝它来处理一个请求。

注意:这些线程根本不必是真正的线程对象。它们可以是 ASIO 异步*调用序列或某些线程框架(如 TBB)中的轻量级任务。

更新:我将为您发布一些伪代码框架,我将如何使用 Boost.Asio 实现服务器。为此,我想介绍一个我发现有助于理解 Asio 执行的小概念:您可以将其视为状态机,其中 async_* 调用是状态转换,而处理程序是状态.通常你有一个 async_* - 每次处理程序执行调用,这意味着你从一种状态转到另一种状态。如果您在一个处理程序中有多个后续 async_* 调用,这意味着该处理程序正在生成辅助执行线程。如果处理程序不调用任何 async_* 函数,则相应的执行线程结束。

现在开始实现。

Thread 0 gies 就像典型的 Asio 教程展示的那样,创建一个套接字并监听传入的连接。唯一的事情是在每个新的客户端连接上都会产生一个新的执行线程(读取:处理程序序列):

accept_handler(client connection) {
async_read(client_request, request_handler) //spawn new thread of execution
async_accept(next client connection, accept_handler) //transition to accept_handler
}

线程 N:以 request_handler 开始:

request_handler(client_request) {
if canProcess
async_send_answer(client, done_handler) //transition to done_handler
else //relay request to first server on list
async_connect(first server on list, connect_handler) //transition to connect_handler
}

done_handler 通常会记录成功的答案并且不会调用另一个async_* 函数,这意味着与客户端的连接将被关闭并且执行线程结束。

将请求发送到其他服务器的处理程序顺序是典型的连接-发送-接收-断开顺序:

connect_handler          -- async_send(request) ---------> send_handler
send_handler -- async_read(answer) ----------> read_handler
read_handler (no answer) -- async_connect(next server) --> connect_handler

如果从其中一台服务器收到答复或列表中没有更多服务器,则循环结束:

read_handler (answer ok)       -- async_send_answer(client) --> done_handler
read_handler (no more servers) -- async_send_fail(client) ----> done_handler

关于c++ - boost::asio - 服务器之间的冲突,双向通信,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17163884/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com