สมมติว่าเรามีเพียร์สองโหนด: โหนดแรกสามารถส่งการร้องขอการเชื่อมต่อไปยังหนึ่งที่สอง แต่ยังที่สองที่สามารถส่งการร้องขอการเชื่อมต่อไปยังที่หนึ่ง จะหลีกเลี่ยงการเชื่อมต่อสองครั้งระหว่างสองโหนดได้อย่างไร เมื่อต้องการแก้ไขปัญหานี้มันจะเพียงพอที่จะทำให้การดำเนินการตามลำดับสำหรับการสร้างการเชื่อมต่อ 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
}
ตัวอย่าง: IP: พอร์ตของโหนด A คือ A: 7001 - พอร์ต IP: ของโหนด B คือ B: 8001
สมมติว่าโหนด A ได้ส่งคำขอเข้าสู่ระบบไปที่โหนด B: 8001 ในกรณีนี้โหนด A เรียกรูทีนการล็อกอินโดยส่งโดยการส่งที่อยู่ที่รับฟังของตัวเอง (A: 7001) ด้วยเหตุนี้เพื่อนบ้าน_tableของโหนด A จึงมีที่อยู่ของรีโมตโหนด (B: 8001): ที่อยู่นี้เชื่อมโยงกับสถานะการเชื่อมต่อ โหนด A กำลังรอให้โหนด B ยอมรับหรือปฏิเสธคำขอล็อกอิน
ในขณะเดียวกันโหนด B อาจส่งคำขอเชื่อมต่อไปยังที่อยู่ของโหนด A (A: 7001) จากนั้นโหนด A อาจประมวลผลคำขอของโหนด B ดังนั้นเพื่อนบ้าน _ ตารางของโหนด B จึงมีที่อยู่ของรีโมต node (A: 7001): ที่อยู่นี้เชื่อมโยงกับสถานะ CONNECTING โหนด B กำลังรอโหนด A ยอมรับหรือปฏิเสธคำขอล็อกอิน
หากฝั่งเซิร์ฟเวอร์ของโหนด A ปฏิเสธการร้องขอจาก B: 8001 ดังนั้นฉันต้องแน่ใจว่าฝั่งเซิร์ฟเวอร์ของโหนด B จะยอมรับคำขอจาก A: 7001 ในทำนองเดียวกันถ้าฝั่งเซิร์ฟเวอร์ของโหนด B ปฏิเสธคำขอจาก A: 7001 ดังนั้นฉันต้องแน่ใจว่าฝั่งเซิร์ฟเวอร์ของโหนด A จะยอมรับคำขอจาก B: 8001
ตามกฎ "ที่อยู่ขนาดเล็ก"ในกรณีนี้โหนด A จะปฏิเสธคำขอเข้าสู่ระบบโดยโหนด B ในขณะที่โหนด B จะยอมรับคำขอจากโหนด A
คุณคิดยังไงเกี่ยวกับที่?