P2P打洞技术详解

2023-05-16

原文:https://rebootcat.com/2021/03/28/p2p_nat_traversal/

何为打洞?(what)

英文翻译

  • NAT traversal : NAT 穿越
  • NAT Hole Punching : NAT 打孔

定义

(UDP) 打洞技术是通过中间公网服务器的协助在通信双方的 NAT 网关上建立相关的映射表项,使得双方发送的报文能直接穿透对方的 NAT 网关(防火墙),实现 P2P 直连。

洞:所谓的洞就是映射规则,外部能够主动与之通信的规则

为何要打洞?(why)

直接连不行吗?

  • NAT 技术的存在,一方面减缓了 IPV4 的需求,使得私网 IP 地址通过映射成公网 IP 地址的方式与外界通信
  • 但另外一方面, NAT 也对安全性做了限制(防火墙),外界不能主动与私网 IP 进行通信

image-20210324201346047

打洞有什么好处?

  • 节省流量
  • 降低中心服务器压力
  • 下载速度快(比如迅雷、直播等)
  • 安全性和私密性

如何打洞?(how)

通常我们说的打洞技术基本上都是使用 UDP 来实现的,当然 TCP 也行,只不过会复杂一点(后面我们讨论一下 TCP 打洞)。

使用中继设备(proxy)

主要利⽤第三⽅的服务器作为中转服务器,⽐如Application Level Gateway (ALG),application server, application server with agent, TURN

有点是稳定可靠,缺点是延迟较⼤,不适合在p2p的⽹络中使⽤。

本质上其实不算 P2P 打洞的范畴了。

直连

基本思路是:A 和 B 互相知道对方的公网 IP:Port,使用对方公网 IP:Port 通信

通过修改通信协议,或者 NAT 设备来帮助节点之前的直接通信,⽐如: tunnel, NAT-PMP, UPnP, MidCom, STUN hole punching, ICE, Teredo等。 其中STUN hole punching⽅法在实践中应⽤最为 广泛。

  • UPnP: 把内网 IP 直接映射为 NAT 外网 IP (纯转发模式),类似公网 IP
  • STUN: 比较出名的打洞协议,本质上就是利用一台或多台公网服务器协助位于不同私网的两个节点 A 和 B 进行打洞。

NAT 设备类型

image-20210324201449678

  • Full Cone NAT: 允许任何外部 IP 任何端⼝连⼊ NAT,只要 NAT 内部 host 产⽣过 IP 端⼝映射。 (不限制任何 IP)

  • Restricted Cone NAT: 只允许外部指定 IP 连⼊当前 NAT,即 NAT 内 host 主动连 接过的 IP。(限制 IP)

  • Port-Restricted Cone NAT:只允许内⽹设备主动 连接过的外⽹ IP 和 Port 连⼊。(限制 IP + Port

  • Symmetric NAT:这种类型的 NAT ⾏为跟端⼝限制型的 NAT 类型相似,不同的是,对于向外连接的不同的 IP 和 Port,NAT 随机分配⼀个 Port 来完成地址转换,完成对外连接。(只要向外的 IP:Port 不一致则映射到不同端口

注意:对于前三种 NAT 设备,内网节点连接不同的 server {IP, Port} 对映射外网端口一致

主要有以上几种,市面上还有少量的其他类型

Full Cone NAT (全锥形)

  • NAT 映射规则形成后,外部其他主机能够主动与之通信

举例如下:

  1. A 位于私网内部
  2. A 访问 https://www.google.com/
  3. NAT-A 记录了映射规则,比如 {local_host,local_port,public_port,dest_host} 等信息
  4. 外部其他主机(比如 google.com) 能主动与 A 通信(通过 A 的 public_ip:public_port)

Restricted Cone NAT(限制型)

在 Full Cone NAT 的基础上多加了一条限制规则:

  • 只允许访问过的 server IP 与之通信

举例如下:还是上面的例子,后续只允许 https://www.google.com/ (对应 IP 203.107.53.50) 与之通信,而不 care 203.107.53.50 的端口号(比如从 6666 端口过来的数据)。

Port-Restricted Cone NAT(端口限制型)

在 Restricted Cone NAT 的基础上多加了一条限制规则:

  • 只允许访问过的 server {IP, Port} 与之通信

举例如下:还是上面的例子,后续只允许 https://www.google.com/ (对应 IP 203.107.53.50) 的 80 端口与之通信,其他端口不行

Symmetric NAT(对称型)

访问规则同 Port-Restricted Cone NAT:

  • 只允许访问过的 server {IP, Port} 与之通信

区别是连接不同的 server {IP, Port},映射到 NAT 上的公网 Port 不一致,且映射规则不确定

有些 NAT 设备会进行简单的 +1 操作实现端口映射,比如:{local_port: 6000, public_port: 6000, Server1},{local_port: 6000, public_port: 6001, Server2},{local_port: 6000, public_port: 6003, Server3}

有些 NAT 设备为了安全性,可能会随机进行端口映射,提高端口猜测的难度。

场景分析

(假设已经获取到⽬标邻居的IP Port 等信息)

  1. 先向公⽹服务器发起请求,探测⾃⼰是不是在⼀个 NAT 下
  2. 如果不在,说明自己是公网节点,可以与目标建立连接(让目标主动连接)
  3. 如果在,则获取⾃⼰的 NAT 类型是什么,根据不同的类型采取相应不同的策略

注意:A 和 B 均要与 server 一致保持连接心跳,确保 NAT 映射端口有效

节点 A 在 NAT 下面,节点 B 在公网环境中

打洞策略:

  • 只要保证节点 A 主动向节点 B 发起连接,两者就可以连接成功

image-20210324212632428

节点 A 和 B 在相同的 NAT 下

打洞策略:

  1. A 从 server 获取 B 的信息,server 同时发给 A 和 B 对方的信息(公网/私网信息)
  2. A 与 B 各自收到 server 的信息后,同时向对方发起连接,公网和私网都发(理论上私网会快一点),一旦收到回复,则停止
  3. 建立连接成功

image-20210324213025505

节点 A 和 B 在不同的 NAT 下(这是我们要重点讨论的)

节点 A 和 B 的 NAT 可能是任意一种 NAT 类型

  • A 和 B 均是锥形 NAT
  • A 和 B 分别是对称型和普通锥形(全锥形,限制型锥形)
  • A 和 B 分别是对称型和 Port-Restricted Cone NAT (端口限制型)
  • A 和 B 都是对称型

A 和 B 均是锥形 NAT

锥形 NAT 之间可以容易的打洞成功,具体流程如下:

image-20210324222800953

以下流程假定已经完成了 NAT 类型探测,A/B 知道自己的 NAT 类型,以及通过 NAT 映射出去的端口 PA1/PB1。

打洞策略:

  1. A 向 server 发起与 B 的打洞请求,server 向 B 转发打洞请求,同时A 向 PB1 直接发送探测包,那么 A 为 B 在 PA1 已经成功打洞,但是 A 的消息无法到达,因为 B 的 NAT 会将不明的地址(PA1) 丢弃。(注意:这里有可能不是丢弃,而是拒绝
  2. B 收到从 server 转发过来的打洞请求后,向 PA1 直接发送探测包,这时 B 的 NAT 可以放行 PA1 的消息了,也就是 B 为 A 在 PB1 上完成了打洞。
  3. 至此,A 和 B 消息能够互通,打洞成功

注意,上面斜体部分,NAT 对不明地址的行为可能是拒绝,待会会讨论。

A 和 B 分别是对称型和普通锥形(全锥形,限制型锥形)

假设 A 是对称 NAT,B 是普通锥形:

image-20210325095314524

打洞策略:

  1. A 向 server 发起与 B 的打洞请求,server 向 B 转发打洞请求,同时发送探测包到 PB1,这个探测包是从 PA2 发出的,不是 PA1(因为对称型)。也就是 A 在端口 PA2 为 PB1 完成打洞,同时 B 的 NAT 会丢弃来自不明地址 PA2 的包。(注意:这里有可能不是丢弃,而是拒绝
  2. B 收到从 server 转发过来的打洞请求,向 PA1 发送初始探测包(一开始不知道 PA2),这个时候 B 已经为 A 在 PB1 打好洞,至此 PA2 的消息能够通过 PB1 到达 B。(注意:因为是普通锥形,不对端口做限制,所以从不同端口 PA2 过来的包能被 B 接受
  3. 经过步骤2,B 可以收到 PA2 的消息,同时结合 A 的 NAT 类型,重新改发探测包到 PA2,于是 A 在 PA2 能收到 PB1 的探测包,至此 A 和 B 消息可以互通,打洞成功

如果 A 和 B 正好角色相反,那么可以调整打洞的方向即可

A 和 B 分别是对称型和 Port-Restricted Cone NAT (端口限制型)

原本大致过程是同上面一种场景,但是由于 B 是端口限制型 NAT,会导致 PB1 只允许 PA1 通过(上面红色字体部分B 已经为 A 在 PB1 打好洞),从而 PA2 过来的包会被 B 的 NAT 拒绝,导致打洞失败

A 和 B 都是对称型

由于 A 和 B 均是对称型 NAT,那么比上面一种场景更严格,A 和 B 探测得到的公网 Port 均会被修改,无法完成打洞

对称型打洞真的没有办法了吗?

我们再来考虑对称型和端口限制型的打洞,由于 B 收到 server 转发过来的打洞请求后,是向 PA1 发送探测包的,因为 B 只知道 PA1(PA1 是 A 与 server 连接是映射的端口号,server 也只知道 PA1),但是 A 由于是对称型 NAT,会从一个新端口 PA2 向 B 发包,但是 B 由于是端口限制型,只允许 PA1 端口的包通过,所以 B 会拒绝 PA2。

还是上面那张图:

image-20210325102706630

A 从 PA2 发向 B 的包一直会被 B 拒绝,也就是说 B 无法在 NAT-B 上为 A 打洞。

那***假如 B 探测包不是发往 PA1 而是 PA2 呢***?那 A 和 B 就能打洞成功。

那么问题来了,B 如何知道 PA2 呢?

通常来讲,有两种办法:

  • 端口探测
  • 端口预测

端口探测

对于对称型的 NAT在映射内网端口的时候,有一些 NAT 设备会采取比较傻瓜的端口分配方法,比如进行简单的线性变化

  • 比如每次分配的端口号递增 1
  • PA2 = (PA1 + PB1 + IPA + IPB) % 65535

对于这种 NAT,要探测这种特性需要用到两台及以上的公网 server,通过与不同的 server 连接映射的公网 Port,归纳总结自己的 NAT 映射规律,那么对于 B 来说,打洞的时候第一次向 A 发包,就直接往 PA2 发包就好了。

端口预测

有一些对称型 NAT 为了安全考虑,分配端口的方法难以预测,比如随机分配端口,那么对于这种情况,如何预测端口号呢?

  • 基于一个理论:生日攻击理论

生日攻击理论讲的是在一个班级里,每个人的生日可能是 365 天里的任何一天,每年有 365 天,如果要让 至少有两人的生日相同的概率超过 50%,问这个班级最少需要多少人?

答案是:(xx)

是不是出乎预料?

生日攻击理论说的直白点就是,利用了远小于样本集的尝试次数,就能够很大概率获得两个相同的碰撞采样结果。

那么针对端口号的样本集 65535,实际是 (1025, 65535],双方随机打洞需要尝试多少次(打多少洞)才能刚好碰撞成功呢?

>>> cat nat_birth_attack.py                                                                                                                                                                                         

#!/usr/bin/env python
#-*- coding:utf8 -*-


import os
import math
from decimal import *

getcontext().prec = 6

def birthday_attack(total, rate):
    k = 0
    while True:
        k += 1
        a,t = 1,1
        for i in range(k):
            a = a * (total - i)
            t = t *  total

        np = Decimal(a) / Decimal(t)
        p = 1 - np
        if p > rate:
            print('total:{0} trytimes:{1}  result:{2} > target_rate:{3} success'.format(total, k, p, rate))
            break
        else:
            print('total:{0} trytimes:{1}  result:{2} < target_rate:{3} failed, continue...'.format(total, k, p, rate))
            continue

    return k



if __name__ == '__main__':
    total_samples = 365
    rate = 0.5
    min_k =  birthday_attack(total_samples, rate)
    print("when total_samples is {0}, if request for rate greater than {1}, then try at least {2} times is ok\n".format(total_samples, rate, min_k))

运行结果:

>>> python nat_birth_attack.py                                                                                                                                                                                      ‹git:master ✘› 11:00.53 四  3 25 2021 >>>
total:365 trytimes:1  result:0 < target_rate:0.5 failed, continue...
total:365 trytimes:2  result:0.002740 < target_rate:0.5 failed, continue...
total:365 trytimes:3  result:0.008204 < target_rate:0.5 failed, continue...
total:365 trytimes:4  result:0.016356 < target_rate:0.5 failed, continue...
total:365 trytimes:5  result:0.027136 < target_rate:0.5 failed, continue...
total:365 trytimes:6  result:0.040462 < target_rate:0.5 failed, continue...
total:365 trytimes:7  result:0.056236 < target_rate:0.5 failed, continue...
total:365 trytimes:8  result:0.074335 < target_rate:0.5 failed, continue...
total:365 trytimes:9  result:0.094624 < target_rate:0.5 failed, continue...
total:365 trytimes:10  result:0.116948 < target_rate:0.5 failed, continue...
total:365 trytimes:11  result:0.141141 < target_rate:0.5 failed, continue...
total:365 trytimes:12  result:0.167025 < target_rate:0.5 failed, continue...
total:365 trytimes:13  result:0.194410 < target_rate:0.5 failed, continue...
total:365 trytimes:14  result:0.223103 < target_rate:0.5 failed, continue...
total:365 trytimes:15  result:0.252901 < target_rate:0.5 failed, continue...
total:365 trytimes:16  result:0.283604 < target_rate:0.5 failed, continue...
total:365 trytimes:17  result:0.315008 < target_rate:0.5 failed, continue...
total:365 trytimes:18  result:0.346911 < target_rate:0.5 failed, continue...
total:365 trytimes:19  result:0.379119 < target_rate:0.5 failed, continue...
total:365 trytimes:20  result:0.411438 < target_rate:0.5 failed, continue...
total:365 trytimes:21  result:0.443688 < target_rate:0.5 failed, continue...
total:365 trytimes:22  result:0.475695 < target_rate:0.5 failed, continue...
total:365 trytimes:23  result:0.507297 > target_rate:0.5 success
when total_samples is 365, if request for rate greater than 0.5, then try at least 23 times is ok

把 total 修改成 65535,概率 rate 修改成 80%,计算得到尝试次数为 460 次。

total:65536 trytimes:460  result:0.801039 > target_rate:0.8 success
when total_samples is 65536, if request for rate greater than 0.8, then try at least 460 times is ok

也就是说对于 B 来说,可以尝试随机往 A 的 460 个不同的端口发探测包,就有 80% 的概率能够正好预测到 NAT-A 随机分配的 PA2。

460 个探测包的代价基本可以忽略不计。

image-20210325113426160

至此,可以完美实现对称型和端口限制型的打洞。然而遗憾的是,对于对称型和对称型打洞,依然无法实现。

再来讨论下 NAT 对陌生地址包的行为

上面能够打洞成功的场景下,都是基于一个前提是 NAT 对陌生地址发来的包采用的是丢弃策略。这里的陌生地址指的是自己没有主动往外发包的 {dest_ip, dest_port} 对。

如果不是丢弃,而是采用黑名单机制呢?为了安全考虑,有一些 NAT 在收到陌生地址的包后,会触发防火墙模块,并且在自己的 deny 列表中增加一项{PA2, PB1},随后自己再往 A 发包的时候,本来打算使用 PB1 进行发包,但是发现 deny 列表里已经存在了 PB1,于是会重新选择一个端口号 PB2 发包。于是对于这种锥形 NAT 会退化成对称型的 NAT。

知道了这个原理,要解决也很容易。

  • 设置有限 TTL,避免惊动对方防火墙
  1. 一开始 A 往 B 发包,可以设置 TTL 为 3,这个数大到足够通过自己的外网 NAT(可能有多层),又会被中间的某个运营商 router 丢弃,从而不会惊动 B 的防火墙模块,同时为 B 打好了洞。

  2. 同理,B 也做类似的操作,为 A 打好洞

  3. A 和 B 两边都等待一段时间,比如 2 s

  4. 再互相发探测包,不用设置 TTL

  5. 打洞成功

关于 TTL 的值设置为多少,需要做一定的探测,不然可能设置过小,也许都没有走出自己的 NAT,设置过大,可能导致惊动了对方的防火墙

总结一下

NAT全锥形限制型锥形端口限制型锥形对称型
全锥形DirectDirectDirectDirect
限制型锥形DirectHole PunchHole PunchHole Punch
端口限制型锥形DirectHole PunchHole PunchHole Punch
对称型DirectHole PunchHole PunchRelay

扩展:讨论一下 TCP 打洞的可行性

TCP 也能实现 NAT 打洞,只不过相比 UDP 会更复杂一点。原因是:

  • 一个UDP套接字由一个二元组来标识,该二元组包含一个目的地址和一个目的端口号;而一个TCP套接字是由一个四元组来标识,包括源IP地址、源端口号、目的IP地址、目的端口号
  • TCP 套接字仅允许建立 1 对 1 的响应,即应用程序将一个套接字绑定到本地的端口后,试图将第二个套接字绑定到该端口的操作都会失败

基本打洞策略如下:

  1. A 和 B 分别位于不同的 NAT 下面
  2. A 启动 tcp client,bind 一个 local_port PA1’,执行 connect 连接公网 tcp server,server 获取 A 的映射公网端口 PA
  3. B 同上,B 启动 tcp client,bind 一个 local_port PB1’,执行 connect 连接公网 tcp server,server 获取 B 的映射公网端口 PB
  4. A 和 B 保持和 server 的连接,不断开,避免各自的 NAT 上的映射规则过期 {PA1’ -> PA} 和 {PB1’ -> PB1}
  5. A 和 B 通过 server 互相获取对方的公网 Port PA1 和 PB1,准备开始打洞
  6. A 新启动一个 tcp 套接字,使用 SO_REUSEADDR/SO_REUSEPORT 绑定到之前与 server 连接的本地端口,也就是 PA1’,并且调用 listen 处于等待监听状态
  7. B 同上,bind PB1’ 并且调用 listen 处于监听状态
  8. A 再新建一个套接字 bind 到之前的端口,调用 connect 发起向 PB1 的连接,也就是 A 往 PB1 发送 syn 包,也就是为 B 打洞,NAT-B 会丢弃这个包
  9. 同时 B也再新建一个套接字 bind 到之前的端口, 也调用 connect 发起向 PA1 的连接,也就是 B 往 PA1 发送 syn 包,也就是为 A 打洞
  10. 假设 A 发送完 syn 之后,B 的 syn 包达到了 NAT-A,NAT-A 能通过,这个时候有的 linux 系统上 A 会认为自己的异步 connect 调用成功,同时利用相同的 seq 发送 SYN+ACK 包 到 PB1,NAT-B 也能顺利通过,再返回 ACK 包,连接建立成功;有的 linux 系统会走正常的 accept 操作,也能顺利建立连接

扩展:讨论一下打洞的有效时间

在 NAT 上的映射规则有失效时间,如果要保持洞口的有效性,需要保持打洞双方的心跳。比如在手机上,这个洞口可能会在 1 min 后失效

扩展:讨论一下多层 NAT 的打洞

我感觉其实单层 NAT 应该是类似的。

Blog:

  • rebootcat.com

  • email: linuxcode2niki@gmail.com

2021-03-28 于杭州
By 史矛革

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

P2P打洞技术详解 的相关文章

  • 05-BTC-网络

    目录 前言 比特币网络的工作原理 比特币网络 比特币网络中的每一个节点维护一个零度节点的集合 比特币系统中 每个节点要维护一个等待上链的交易的集合 比特币网络的传播属于best effort 前言 学习肖臻老师的 区块链技术与应用 公开课笔
  • vue父子组件在不同情况下生命周期的执行顺序

    在分析父子组件生命周期之前 我们先核实一次两个路由 不包含子组件 之间切换 其生命周期的执行顺序 在这用到两个路由 新闻路由和top路由 名字只做区分 没有其他含义 1 首先切换到新闻路由 执行顺序 beforeCreate gt crea
  • 数据结构练习题-算法设计题-线性表

    算法设计题 1 将两个递增的有序链表合并为一个递增的有序链表 要求结果链表仍使用原来两个链表的存储空间 不另外占用其它的存储空间 表中不允许有重复的数据 题目分析 合并后的新表使用头指针Lc指向 pa和pb分别是链表La和Lb的工作指针 初
  • 最后一次实验

    拓扑图 实验要求 拓扑分析 先分ip 然后分vlan然后配ip 配路由 设备配置和配置解析 sw1 sw2 r1 r2 r3 实验结果
  • T系接口源数据格式

    item apiStack name esi value endpoint mode android osVersion 9 26 0 protocolVersion 3 0 ultronage true data dinamic TB d
  • 线程池ExecutorService

    1 线程池创建方式 1 通过Executors创建线程池 import java util concurrent ExecutorService import java util concurrent Executors public cl
  • 【科普】波特率和比特速率的理解

    什么是波特率 单位时间内传输的码元个数称为波特率 单位为 Baud 那码元又是什么呢 码元又称为 符号 即 symbol 维基百科上对码元的解释 持续一段固定时间的通信信道有效状态就是码元 这么解释比较抽象 可以解释码元的物理意义 在通信信
  • 【gis系列】等高线创建dem,以及高程分析,坡度分析,坡向分析

    绝对原创 首先 我们要整理一份cad的文件格式 这里我不说那么多 就是在某某地图下载后 方法很多 可以通过qgis globalmapper来操作数据 以及一些普通的地图软件直接生成 这里呢 然后进入cad 把里面的高程标注信息给删除掉 图
  • 1093: 数1的个数

    存限制 128 MB 题目描述 给定一个十进制正整数n 1 n 10000 写下从1到n的所有整数 然后数一下其中出现的数字 1 的个数 例如当n 2时 写下1 2 这样只出现了1个 1 当n 12时 写下1 2 3 4 5 6 7 8 9
  • IP包头&ARP协议笔记

    一 IP包头分析 1 帧中的IP包头 从版本到可选项 其中2为帧头 注 1 IP包头最小长度 20字节 即可选项以前部分 IP包头长度是可变的 2 可选项最长可以是40个字节 故IP包头最长可以是60个字节 1 版本 4 说明是IPv4 2
  • Android 可以进行点对点自组织网络吗?

    是否可以将 Android 设置为 ad hoc 对等 wifi 模式 例如 我想让一部电话广播一条消息 并让网络中的所有对等方接收广播 而无需服务器 我想使用 wifi 因为蓝牙范围更有限 这是有关您请求的功能的错误报告 它的状态是 已审
  • C++ Winsock P2P

    Scenario 有没有人有任何使用 Winsock 在 C 中进行点对点 p2p 网络的好例子 这是我对特别需要使用这项技术的客户的要求 天知道为什么 我需要确定这是否可行 任何帮助将不胜感激 EDIT 我想避免使用库 以便我可以理解底层
  • 如何修复 InvalidStateError:没有远程 SDP 时无法添加 ICE 候选者

    我正在创建一个 webRTC 视频聊天 当从 Firefox 发起呼叫时显示呼叫者所有活动成员 并且接收者使用 chrome 此错误显示 未捕获 承诺 DOMException 无法在 RTCPeerConnection 上执行 addIc
  • peerjs/webrtciceConnectionState 失败

    我已经尝试解决这个问题有一段时间了 我正在尝试使用peerjs 建立一个简单的连接 我可以成功连接到具有 id 的对等点USER ID 但是 他们无法连接到我 当他们尝试连接时 我收到以下日志 iceConnectionState更改为fa
  • UDP打洞帮助

    我正在尝试使用点对点将互联网网络添加到我的游戏中 我已经实现了仅 LAN 版本 它使用 NET 的对等类在本地网络内进行连接 我意识到我需要使用 UDP 打洞来建立与防火墙后面的其他客户端的连接 这就是我开始实施它的方式 该服务器是一个 H
  • 在 Kademlia 中,为什么建议使用 160 位节点 ID 和密钥而不是 128 位?

    Kademlia 论文指出 节点被分配了随机的 160 位 ID 和密钥 这是一个严格的限制吗 如果我觉得足够好 我还可以继续使用 128 位密钥空间吗 选择这个长度是因为用作哈希表键的哈希函数的 SHA1 输出 160 位 这是当时使用最
  • 使用中间服务器创建点对点连接

    我想连接两个客户端 通过 TCP IP 套接字 客户端可以使用中间服务器发现彼此 一旦客户端发现彼此 服务器就不应该有任何参与 我对此做了一些研究 发现很多人建议JXTA 但我想自己从头开始创建协议 因为将来我可能也必须使用 WebSock
  • WCF 是否支持点对点实现?

    我正在尝试在 LAN 内实现点对点消息传递和文件共享实用程序 那么 WCF 支持 p2p 吗 有人尝试过通过 WCF 进行文件共享吗 是的 它确实 请参见如何在对等网络中设计状态共享 http msdn microsoft com en u
  • 自动启用从 Internet 访问端口 4900 的方法

    我正在编写一个在端口 4900 上运行的自定义 p2p 程序 在某些情况下 当用户位于路由器后面时 无法从互联网访问该端口 是否有一种自动方式可以从互联网访问该端口 我不太确定其他 p2p 应用程序是如何工作的 有人能解释一下吗 简而言之
  • 是否可以通过互联网在两个移动设备 (iPhone) 之间连接套接字?

    是否可以通过互联网在两个移动设备 iPhone 之间连接套接字 我正在尝试发现每个设备的IP并直接连接 我知道可以使用 Bonjour 来完成 但这只适用于本地网络 我需要通过互联网在两个设备之间建立高速连接 Thanks 如果你有两个 I

随机推荐