java网络编程消息传递的协调

发布于 2024-10-03 02:10:34 字数 1482 浏览 3 评论 0原文

我有 2 个进程运行在不同的机器上,它们通过 TCP 套接字进行通信。
这两个进程都有既充当服务器又充当客户端的代码。
ProcessA 打开了一个绑定在 portX 的服务器套接字,ProcessB 打开了一个绑定在 portY 的服务器套接字。
ProcessA 打开客户端套接字以与 ProcessB 连接并开始作为客户端发送消息 并接收响应(当然是通过相同的 TCP 连接)。
ProcessB 一旦接收到消息并对其进行处理,它就会发送响应,但也可以通过第二个 tcp 连接发送消息,即 ProcessB 已打开到 ProcessA 的 portX 的客户端套接字。
因此消息流通过 2 个不同的 TCP 连接进行。
我的问题如下:理所当然地认为这种“架构”不能改变并且必须保持原样:
我遇到的问题是,消息间歇性地通过 ProcessB 打开客户端套接字的 tcp 连接从 ProcessB 发送到 ProcessA,在消息通过 ProcessA 作为客户端连接的 tcp 连接作为响应从 ProcessB 发送到 ProcessA 之前到达 processA套接字。
即两个流程都发生

(1)  
ProcessA ---->(msg)----> ProcessB(PortY)  (TCP1)
ProcessB does processing   
ProcessB(portY)--->(response)----->ProcessA (TCP1)  
ProcessB--->(msg)----->ProcessA(portX)  (TCP2)

(2)  
ProcessA ---->(msg)----> ProcessB(PortY)  (TCP1)
ProcessB does processing   
ProcessB--->(msg)----->ProcessA(portX)  (TCP2)
ProcessB(portY)--->(response)----->ProcessA  (TCP1)

编辑(在 ejp 请求之后) 在从 ProcessB 的服务器 portY 作为回复发送的消息到达 processA 之前,如何强制/确保 ProcessB 不会通过 ProcessB 有一个向 ProcessA 的服务器 portX 打开的客户端套接字的连接发送消息?即只有上述流程(1)。
请注意,processB 是多线程的,并且处理过程并不简单。

更新: 可能这是我的误解,但是当进程通过套接字发送数据并将控制权返回给应用程序时,这并不意味着接收方已收到数据。 那么,如果一个进程通过 2 个套接字发送数据,操作系统是否存在竞争条件?

更新2
我从维杰·马修那里得到答复后:
如果我按照建议进行锁定,是否可以保证操作系统(即IP层)将按顺序发送数据?即完成一次传输,然后发送下一次?或者我会将它们复用并遇到相同的问题?

谢谢

I have 2 processes running in different machines which are communicating via TCP sockets.
Both processes have code that acts both as a server and as a client.
I.e. ProcessA has opened a server socket that binds at portX and ProcessB has opened a server socket bind at portY.
ProcessA opens a client socket to connect with ProcessB and start sending messages as a client
and receiving responses (over the same tcp connection of course).
ProcessB once it receives a message and processes it, it sends the response, but also could send a message over the second tcp connection, i.e. where ProcessB has opened a client socket to portX of ProcessA.
So the flow of messages are over 2 different tcp connections.
My problem is the following: Taking as granted that this "architecture" can not change and must stay as is:
I have the problem that intermittently, the messages send from ProcessB to ProcessA over the tcp connection that ProcessB has opened the client socket, arrive at processA before the messages send as responses from ProcessB to ProcessA over the tcp connection that ProcessA has connected as a client socket.
I.e. Both flows occur

(1)  
ProcessA ---->(msg)----> ProcessB(PortY)  (TCP1)
ProcessB does processing   
ProcessB(portY)--->(response)----->ProcessA (TCP1)  
ProcessB--->(msg)----->ProcessA(portX)  (TCP2)

(2)  
ProcessA ---->(msg)----> ProcessB(PortY)  (TCP1)
ProcessB does processing   
ProcessB--->(msg)----->ProcessA(portX)  (TCP2)
ProcessB(portY)--->(response)----->ProcessA  (TCP1)

EDIT (after ejp request)
How can I enforce/make sure that ProcessB does not send a msg over the connection that ProcessB has a client socket open to server portX of ProcessA, before the message send as a reply from server portY of ProcessB arrives at processA? I.e. to have only flow (1) of the above.
Note that processB is multithreaded and the processing is non-trivial.

UPDATE:
May be it is my misconception, but when a process sends data over socket, and control is returned to application, this does not mean that the receiving side has received the data.
So if a process sends data over 2 sockets, is there a race condition by OS?

UPDATE2
After answer I got from Vijay Mathew:
If I did a locking as suggested, is there a guarantee that OS (i.e. IP layer) will send the data in order? I.e. finish one transmission, then send the next? Or I would they be multiplexed and have same issue?

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

醉酒的小男人 2024-10-10 02:10:34

显而易见的解决方案是:

LockObject lock;

ProcessA ---->(msg)----> ProcessB(PortY)

// Processing the request and sending its response 
// makes a single transaction.
synchronized (lock) {
    ProcessB does processing   
    ProcessB(portY)--->(response)----->ProcessA (TCP1)
}

// While the processing code holds the lock, B is not
// allowed to send a request to A.
synchronized (lock) {
    ProcessB--->(msg)----->ProcessA(portX)  (TCP2)
}

The obvious solution is:

LockObject lock;

ProcessA ---->(msg)----> ProcessB(PortY)

// Processing the request and sending its response 
// makes a single transaction.
synchronized (lock) {
    ProcessB does processing   
    ProcessB(portY)--->(response)----->ProcessA (TCP1)
}

// While the processing code holds the lock, B is not
// allowed to send a request to A.
synchronized (lock) {
    ProcessB--->(msg)----->ProcessA(portX)  (TCP2)
}
浸婚纱 2024-10-10 02:10:34

同步问题可能不在于 TCP 协议,而在于线程处理程序选择消息到达时唤醒哪个线程。我从你的问题的性质了解到,PortX“(消息)”在 PortY“(响应)”之后很快发送。这意味着线程处理程序有时可以选择要唤醒两个侦听线程中的哪一个。

解决该问题的一种简单但丑陋且不完整的方法是在响应和下一条消息之间插入短暂的睡眠。睡眠时间必须足够长,才能确信其他进程在收到下一条消息之前已经醒来并收到响应。这种方式是不完整的,因为尽管您正在增加正确同步处理的更改,但操作系统负载和网络拥塞等问题总是会共同将您的消息推回到您的响应之后。然后你又回到了起点。另一件丑陋的事情是,睡眠会浪费时间,并且会降低你的最大吞吐量。只是频率比较低而已。所以...

为了彻底解决这个问题,您需要某种方式让每个套接字侦听器知道它刚刚收到的消息是否是下一个要处理的消息,或者是否可能有必须先处理的较早消息。为此,请按顺序对每个进程发送的所有消息进行编号。然后接收进程就知道是否缺少任何东西。

您必须想出一种方法,让每个套接字上的侦听器在它们之间进行协商,以确保收到的消息按传输顺序进行处理。有许多实用的解决方案,但它们在抽象、概念层面上都是同一件事。

线程 1:
A) ProcessA(PortX) 线程收到消息并唤醒。
B) 如果序列号表明有消息丢失,则
B1) 在 ProcessA(PortY) 上同步并 wait()。
B2) 醒来后,回到B)
C) {没有消息丢失} 处理消息。
D) 回到 A)

线程 2:
A) ProcessA(PortY) 收到响应并唤醒。
B) 处理响应。
C)notifyAll()。
D) 回到 A)

最通用的实际解决方案可能涉及单个套接字侦听器实例,将所有新消息添加到 PriorityQueue,以便最早发送的消息始终到达队列的头部。然后,线程 1 和线程 2 都可以等待该实例,直到它们可以处理的消息到达。

一个更简单但可扩展性较差的解决方案是让每个线程自己进行侦听和等待,并在处理后通知(响应)处理程序。

祝你好运,尽管经过这么长时间,它可能已经解决了。

The synchronisation problem may not be in the TCP protocol, but in the thread handler choosing which thread to wake up when the messages arrive. I understand from the nature of your question that the PortX "(Msg)" is sent very quickly after after the PortY "(Response)". This means that the thread handler may occasionally have a choice as to which of the two listening threads it will wake.

A simple, but ugly and incomplete, way to fix the problem is to insert a short sleep between the response and the next message. The sleep would have to be long enough to be confident that the other process will have woken up to the response before the next message is received. This way is incomplete because although you are increasing the changes of properly synchronising your processing, issues like OS load and network congestion can always conspire to push your message right back up behind your response. And then you're back where you started. The other bit of ugliness is that the sleeping wastes time and will reduce your maximum throughput. Just less often. So...

To completely resolve the issue, you need some way for each socket listener to know whether the message it just received is the next one to be processed, or whether there might be earlier messages that have to be processed first. Do this by sequentially numbering all messages sent by each process. Then the receiving process knows if anything is missing.

You will have to think of a way for the listeners on each socket to confer between themselves to ensure that messages received are processed in order of transmission. There are a number of practical solutionsm, but they all amount to the same thing at the abstract, conceptual level.

THREAD 1:
A) ProcessA(PortX) thread receives a message and wakes.
B) IF the sequence number indicates that there is a missing message, THEN
B1) synchronize on ProcessA(PortY) and wait ().
B2) On waking, back to B)
C) {no message is missing} Process the message.
D) Back to A)

THREAD 2:
A) ProcessA(PortY) receives a response and wakes.
B) Process the response.
C) notifyAll ().
D) Back to A)

The most generic practical solutions would probably involve a single socket listener instance adding all new messages to a PriorityQueue so the earliest-sent messages always go to the head of the queue. Then Thread 1 and Thread 2 could both wait on that instance until a message arrives that they can process.

A simpler but less extensible solution would be to have each thread do it's own listening and waiting with the (response) handler notifying after processing.

Good luck with it, although after all this time, it's probably solved already.

小梨窩很甜 2024-10-10 02:10:34

显而易见的问题是你为什么关心?如果您有需要在任一端同步的操作,请执行此操作。不要指望 TCP 会为你做这件事,这不是它的用途。

The obvious question is why do you care? If you have operations that need to be synchronized at either end, do so. Don't expect TCP to do it for you, that's not what it's for.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文