假设我们有两个对等节点:第一个节点可以向第二个节点发送连接请求,但是第二个节点可以向第一个节点发送连接请求。如何避免两个节点之间的双重连接?要解决此问题,顺序执行为创建入站或出站TCP连接而执行的操作就足够了。
这意味着每个节点都应按顺序处理每个新的连接创建操作,包括传入连接和传出连接。这样,在从节点接受新的传入连接之前或在向节点发送连接请求之前,维护已连接节点的列表,只需检查该节点是否已存在于列表中就足够了。
为了使创建连接的操作顺序进行,对连接的节点列表执行锁定就足够了:实际上,对于每个新连接,新连接的节点的标识符都添加到该列表中。但是,我想知道这种方法是否会导致分布式死锁:
- 第一节点可以向第二节点发送连接请求;
- 第二节点可以向第一节点发送连接请求;
- 假设两个连接请求不是异步的,则两个节点都锁定所有传入的连接请求。
我该如何解决这个问题?
更新:但是,每次创建新的(传入或传出的)连接时,我仍然必须锁定列表,因为其他线程可能会访问该列表,因此仍然存在死锁问题。
更新2:根据您的建议,我编写了一种算法,以防止相互接受登录请求。由于每个节点都是对等节点,因此它可以具有一个客户端例程来发送新的连接请求,以及一个服务器例程来接受传入的连接。
ClientSideLoginRoutine() {
for each (address in cache) {
lock (neighbors_table) {
if (neighbors_table.contains(address)) {
// there is already a neighbor with the same address
continue;
}
neighbors_table.add(address, status: CONNECTING);
} // end lock
// ...
// The node tries to establish a TCP connection with the remote address
// and perform the login procedure by sending its listening address (IP and port).
boolean login_result = // ...
// ...
if (login_result)
lock (neighbors_table)
neighbors_table.add(address, status: CONNECTED);
} // end for
}
ServerSideLoginRoutine(remoteListeningAddress) {
// ...
// initialization of data structures needed for communication (queues, etc)
// ...
lock(neighbors_table) {
if(neighbors_table.contains(remoteAddress) && its status is CONNECTING) {
// In this case, the client-side on the same node has already
// initiated the procedure of logging in to the remote node.
if (myListeningAddress < remoteListeningAddress) {
refusesLogin();
return;
}
}
neighbors_table.add(remoteListeningAddress, status: CONNECTED);
} // end lock
}
示例: 节点A的IP:端口为A:7001-节点B的IP:端口为B:8001。
假设节点A已向节点B发送了登录请求:8001。在这种情况下,节点A通过发送自己的侦听地址(A:7001)进行发送来调用登录例程。结果,节点A的neighbors_table包含远程节点的地址(B:8001):此地址与CONNECTING状态关联。节点A正在等待节点B接受或拒绝登录请求。
同时,节点B可能已经向节点A的地址发送了连接请求(A:7001),则节点A可能正在处理节点B的请求。因此,节点B的neighbors_table包含远程节点的地址。节点(A:7001):此地址与CONNECTING状态关联。节点B正在等待节点A接受或拒绝登录请求。
如果节点A的服务器端拒绝了B:8001的请求,那么我必须确保节点B的服务器端将接受来自A:7001的请求。同样,如果节点B的服务器端拒绝了A:7001的请求,那么我必须确保节点A的服务器端将接受来自B:8001的请求。
根据“小地址”规则,在这种情况下,节点A将拒绝节点B的登录请求,而节点B将接受来自节点A的请求。
您对此有何看法?