Suponha que tenhamos dois nós de mesmo nível: o primeiro nó pode enviar uma solicitação de conexão para o segundo, mas também o segundo pode enviar uma solicitação de conexão para o primeiro. Como evitar uma conexão dupla entre os dois nós? Para resolver esse problema, seria suficiente tornar sequenciais as operações executadas para criar conexões TCP de entrada ou saída.
Isso significa que cada nó deve processar sequencialmente cada nova operação de criação de conexão, tanto para conexões de entrada quanto para conexões de saída. Dessa maneira, mantendo uma lista de nós conectados, antes de aceitar uma nova conexão de entrada de um nó ou antes de enviar uma solicitação de conexão a um nó, será suficiente verificar se esse nó já está presente na lista.
Para tornar sequenciais as operações de criação de conexões, é suficiente executar um bloqueio na lista de nós conectados: de fato, para cada nova conexão, o identificador do novo nó conectado é adicionado a esta lista. No entanto, gostaria de saber se essa abordagem pode causar um conflito distribuído :
- o primeiro nó pode enviar uma solicitação de conexão para o segundo;
- o segundo nó pode enviar uma solicitação de conexão para o primeiro;
- assumindo que as duas solicitações de conexão não sejam assíncronas, os dois nós bloqueiam todas as solicitações de conexão recebidas.
Como eu poderia resolver esse problema?
ATUALIZAÇÃO: No entanto, ainda tenho que bloquear a lista toda vez que uma nova conexão (de entrada ou saída) é criada, já que outros threads podem acessar essa lista, e o problema de conflito ainda permanece.
ATUALIZAÇÃO 2: Com base no seu conselho, escrevi um algoritmo para impedir a aceitação mútua de uma solicitação de login. Como cada nó é um par, pode haver uma rotina de cliente para enviar novas solicitações de conexão e uma rotina de servidor para aceitar conexões de entrada.
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
}
Exemplo: O IP: porta do nó A é A: 7001 - O IP: porta do nó B é B: 8001.
Suponha que o nó A tenha enviado uma solicitação de login ao nó B: 8001. Nesse caso, o nó A chama a rotina de login enviando enviando seu próprio endereço de escuta (A: 7001). Como conseqüência, a tabela vizinhos_ do nó A contém o endereço do nó remoto (B: 8001): esse endereço está associado ao estado CONNECTING. O nó A está aguardando o nó B aceitar ou negar a solicitação de login.
Enquanto isso, o nó B também pode ter enviado uma solicitação de conexão para o endereço do nó A (A: 7001), e o nó A pode estar processando a solicitação do nó B. Portanto, a tabela de vizinhos do nó B contém o endereço do controle remoto. nó (A: 7001): esse endereço está associado ao estado CONNECTING. O nó B está aguardando o nó A aceitar ou negar a solicitação de login.
Se o lado do servidor do nó A rejeitar a solicitação de B: 8001, devo ter certeza de que o lado do servidor do nó B aceitará a solicitação de A: 7001. Da mesma forma, se o lado do servidor do nó B rejeitar a solicitação de A: 7001, devo ter certeza de que o lado do servidor do nó A aceitará a solicitação do B: 8001.
De acordo com a regra "pequeno endereço" , nesse caso, o nó A rejeitará a solicitação de login pelo nó B, enquanto o nó B aceitará a solicitação do nó A.
O que você acha disso?