如何绕过已连接的聚会

时间:2018-12-15 14:24:59

标签: c sockets asynchronous networking connection

根据我的程序体系结构,如何确定如何解除两方的连接同步一直很困难。这是一个P2P聊天。程序启动时,每一方都将自动相互连接。连接过程是异步的。 当有传入连接时,从侦听器调用信号,信号处理程序负责连接。因此,“接受”也是异步的。

这最终将使两个用户连接两次。将有两个连接。 双方都是服务器和客户端。这是不需要的。 现在,我尝试了很多方法来解决此问题,但没有一个真正起作用。 例如,我在侦听器信号处理程序中检查了该IP上的套接字是否已经存在,如果断开,则将其断开并返回。但是连接的设计方式是另一端将继续尝试连接。

设计它的正确方法是什么?有哪些替代方法?

1 个答案:

答案 0 :(得分:2)

让我们看一下四个同行的情况:
Four peers
如果每个对等点都与其他每个对等点连接,则每对对等点之间将有两个连接。 (如果有N个对等体,则有N(N-1)/ 2个唯一对。)

在上图中,对等方按其名称(A,B,C,D)排序。与字母名称在字母后面的对等方的连接为蓝色,字母名称与字母表前面的对等方的连接为红色。

如果您可以以某种方式订购对等方,则仅按顺序在自己之前连接到对等方(红色),并在自己之后接受来自对等方的连接(再次为红色),将确保每对唯一的对等方只有一个连接

假设您有N个对等方,并且您以某种方式从0N-1(包括下同)对它们进行排序。然后,对等体i需要建立accept()个对等体之间的N-1-i连接,以及connect()i个对等体之间的连接。

当然,实践中没有那么简单的事情。问题在于,同行可能会在不同的时间出现,而不是同时出现。如果另一端还没有与该地址和端口相对应的侦听套接字,则连接将失败。因此,最重要的是首先建立监听套接字,确保积压足够大,然后再建立连接。

如果我们查看GIO GSocket(因为这似乎是OP所使用的),则假定所有同行都同意他们的订购,解决方案就相当简单。

  1. 所有对等方都使用g_socket_new()g_socket_bind()g_set_backlog()g_socket_listen()创建监听套接字。积压的数量至少应为对等体的数量(少于1个)。

    如果可以在运行时“邀请”新的对等方,请使用较大的积压。如果不能邀请新的对等方,则该顺序中的最后一个对等方不需要侦听套接字,因为它只会建立连接,而不接受传入的连接。

  2. i个对等方(顺序为0的第一个对等方)使用i创建g_socket_new()套接字以在排序之前连接到对等方g_socket_bind(),可以选择g_socket_set_blocking()(使连接无阻塞)和g_socket_connect()

    如果使用g_socket_set_blocking()使套接字无阻塞,则对等方可以循环进入g_socket_check_connect_result()g_socket_condition_check(),以等待所有连接完成。

    请注意,由于每个对等方创建其传入套接字的时间的实际差异,连接可能会失败(因为另一端尚未启动)。在这种情况下,您只需要重试即可;即再次致电g_socket_connect()

    (您还可以使用g_socket_create_source()从套接字创建GSource,将其视为事件源。)

  3. 这时,应将入站连接积压在OS网络堆栈中(或将要积压),因此对等i应使用g_socket_accept()接受来自{{1 }}依次查看。


我个人会使用一种不同的体系结构/方法,该体系结构/方法可以动态管理对等列表。

比方说,每个对等方都有一个唯一的标识符。 (例如,可以是映射了IPv6的地址和端口,或者是用户昵称及其公钥。)

建立连接后,连接方将发送初始握手,该握手包含其自己的标识符以及它尝试连接的一方的标识符。接受新连接后,将收到初始握手(在某个超时间隔内)。如果连接方是新的,它将被添加到连接的对等方列表中。如果已经连接,则将断开新连接或现有连接(在发送说明断开原因的数据包之后)。

这还将允许“邀请”,并在网格上共享对等连接信息。