我有两个进程在不同的机器上运行,这些进程通过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不会通过ProcessB将客户端套接字打开到ProcessA的服务器端口X的连接发送消息,之后作为来自ProcessB的服务器端口Y的消息发送到processA?即只有上述的流程(1) 请注意,processB是多线程的,处理非常重要。
更新 可能是我的误解,但是当进程通过套接字发送数据并且控制权返回给应用程序时,这并不意味着接收方已经接收到数据。 因此,如果进程通过2个套接字发送数据,操作系统是否存在竞争条件?
UPDATE2
回答后我从Vijay Mathew那里得到了:
如果按照建议进行锁定,是否可以保证OS(即IP层)按顺序发送数据?即完成一次传输,然后发送下一个?或者我会将它们复用并有同样的问题吗?
由于
答案 0 :(得分:1)
显而易见的解决方案是:
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)
}
答案 1 :(得分:1)
同步问题可能不在TCP协议中,而是在线程处理程序中选择在消息到达时唤醒哪个线程。我从你的问题的性质中了解到PortX“(Msg)”在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都可以在该实例上等待,直到消息到达它们可以处理。
一个更简单但不易扩展的解决方案是让每个线程自己监听并等待处理后通知的(响应)处理程序。
祝你好运,虽然毕竟这一次,它可能已经解决了。
答案 2 :(得分:0)
显而易见的问题是你为什么关心?如果您需要在任一端同步操作,请执行此操作。不要指望TCP会为你做这件事,这不是它的用途。