避免 P2P 网络架构中的同时双向连接

Avoiding simultaneous bi-directional connections in a P2P network architecture

好吧,我是一名合格的程序员,多年来一直在做各种奇迹,但我终于要问一个我完全无法解决的问题。我希望 Stack Overflow 能在这么多年后再次拯救我的生命。


这是关于唯一对问题。我正在使用 GIO 的 GSocketClientGSocketService 高级 API 来建立异步连接并接受两个对等点之间的传入连接(显然每个点都使用相同的程序)。由于对等点可以同时相互连接,这会导致 2 个连接,而只需要一个连接。

我尝试了太多的事情,包括删除绑定 IP 号码先于另一个的连接(这样一个连接就被丢弃),但这仍然并不总是有效,所以我现在头晕目眩,应该先做什么和在哪里。

为了不让我尝试过的所有事情过于复杂化,我将直截了当地问:在这种情况下,正确的方法是什么?

这很艰难,但经过 3 天的坚持思考和测试..我有一个解决方案。

我坚信这个问题不应该被否决(特别是因为它看起来是 "pretentious and pompous"),但我们不能总是得到最好的 S/O 可以吗。

问题

当两个对等点想要同时相互连接时 将有两个连接,而只需要一个。 在接受、连接和处理时更加复杂 是异步的,可以随时发生,也可以同时发生 对等点分别使用相同的程序,因此是一个相当严格的 P2P 架构。 这是拜占庭将军问题的经典示例,这是最难的计算机问题之一。

解决方案

该解决方案不涉及完全同步,因此缺少异步连接、接受和处理的要点,也不需要在处理后断开连接。这个强大的解决方案背后有 3 个主要思想。

  1. 某种记录(我使用 GList)包含 "pending" IP
  2. 将 IP 转换为数字的函数
  3. 系统等待并授予权限

如果正确实施并用在正确的地方,你就有了。现在详细一点。

包含 "pending" IP 的某种记录

正如我所说,这可以是一个列表。附加、搜索和删除操作必须由互斥体锁定。从列表中删除 IP 必须发生在接受时、搜索后和断开连接通知程序中。

IP转数字函数

例如rScanf = sscanf(ip, "%u.%u.%u.%u", &bytes[0], &bytes[1], &bytes[2], &bytes[3]);

然后将每个数字相加。这用作排他性标准。 if(remote_ip_number > local_ip_number) 仅对其中一位同行成立。

系统等待并授予权限

连接必须等待接受线程的许可。虽然调用一定是阻塞的,但不会造成任何开销,大多数情况下会return立即。 在收到许可(拒绝(1)或授予(2))后,它会发送 ACK(3)和 returns(1- 断开连接)或继续。主机等待 ACK,然后以相同的方式 returns(断开连接)或继续(如果授予权限)。

主办方应根据排他性标准来决定是拒绝还是同意。 首先,它检查 IP 是否存在于挂起连接列表中(基本上意味着该程序也尝试连接),如果存在,如果 IP 条件匹配,则发送授权或拒绝。


在 connect 的同步调用中,在它实际尝试连接之前,将 IP 添加到挂起连接列表中很重要,而且程序的构建方式也很重要,首先它连接到它想连接的任何人,然后是主机,以便注册第一个挂起的 IP。这在可预测性方面略有优势。

connect(PETER); /* adds PETER ip to listPending */
connect(JOHN); /* adds JOHN ip to listPending */

host(ME); /* Gives permission if IP does not exist in listPending or it does but local ip number < remote ip number */