두 개의 피어 노드가 있다고 가정합니다. 첫 번째 노드는 두 번째 노드에 연결 요청을 보낼 수 있지만 두 번째 노드는 첫 번째 노드에 연결 요청을 보낼 수 있습니다. 두 노드 간의 이중 연결을 피하는 방법은 무엇입니까? 이 문제를 해결하려면 인바운드 또는 아웃 바운드 TCP 연결을 만들기 위해 수행 된 작업을 순차적으로 수행하면 충분합니다.
즉, 각 노드는 들어오는 연결과 나가는 연결 모두에 대해 각각의 새 연결 작성 작업을 순차적으로 처리해야합니다. 이러한 방식으로, 연결된 노드 목록을 유지 관리하거나, 노드에서 새로운 수신 연결을 수락하기 전에 또는 노드로 연결 요청을 보내기 전에이 노드가 이미 목록에 있는지 확인하면 충분합니다.
연결 작성 조작을 순차적으로 수행 하려면 연결된 노드 목록 에서 잠금 을 수행하는 것으로 충분합니다 . 실제로 각 새 연결마다 새 연결된 노드의 ID가이 목록에 추가됩니다. 그러나이 접근법이 분산 교착 상태를 일으킬 수 있는지 궁금합니다 .
- 제 1 노드는 제 2 노드에 연결 요청을 전송할 수 있고;
- 제 2 노드는 제 1 노드에 연결 요청을 전송할 수 있고;
- 두 개의 연결 요청이 비동기 적이 지 않다고 가정하면 두 노드 모두 들어오는 연결 요청을 잠급니다.
이 문제를 어떻게 해결할 수 있습니까?
업데이트 : 그러나 다른 스레드 가이 목록에 액세스 할 수 있으므로 교착 상태 문제는 여전히 남아 있기 때문에 새로운 (들어오는 또는 나가는) 연결이 생성 될 때마다 여전히 목록을 잠 가야합니다.
업데이트 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의 요청을 수락합니다.
그것에 대해 어떻게 생각하세요?