搜索了一下,基本没有C#的代码可供参考,
有的完全依靠服务端转发数据。
还有乱贴代码没有测试勿人子弟一大群。废话就算了,言归正卷了。
假设A要和B之间通讯(AB均在不同路由下),必须借助S进行沟通调节.
A连接B,的步骤就是A先告诉S我要连接B,S传话给B有个小子要和你单挑,B对A的路由说放马过来吧,A马上向B的路由发送单条信息。(这个过程参照网上的说法总结,不知道对不对)现在有个问题了
A,B和S的连接必须是TCP连接,。(我想应该是的,要不怎么去及时去给A,B传话)
B对A的路由说放马过来,但是它应该对那个路由端口说呢??
A又向B的路由发信息,它又应该对那个端口说呢??
A和B都不知道路由开的是那个端口。

解决方案 »

  1.   

    没做过这方面的,不过觉得S应该算是个中转服务器吧,负责A与B的通讯。
      

  2.   

    A开放的端口S必须知道.或协定前知道.或让B在此前也知道
    这个端口应该不是路由的端口吧.是程序运行那台机器开放的端口吧.
    必须是TCP连接的?不是必须吧?要不怎么叫UDP穿透呢?
      

  3.   

    补充一点,连接之前,A向S发一个新连接,S把A路由的端口发送到B,
    B向S发一个新连接,,S把B路由的端口发送到A,
    A向B路由的端口发送测试连接,同时向后续的10个端口发,
    B向A路由的端口发测试连接,同时向后续10个端口发,
    理论上应该有一定机会碰到,不过不用测试就知道在大规模应用中绝对是垃圾方法。
    因为路由也不是为你个人服务的。
      

  4.   

    TCP和UDP应该是在一个级别上,
    位于不同的网络之间的机器无法直接通信,除非借助于一台Server,
    也就是你说的这个中间机器,
    两台client不需要知道互相之间的信息,
    所必须的是,两台机器如何和服务器通信。
      

  5.   

    确实是我说的地方有点错误了.
    回想以前我做的..大约是这样.
    A,B,启动时向S登记自已的信息..如是内网则是公网的ip地址加路由随机的端口号.
    因为处于路由后面的机器不能和另一个处于路由后面的机器通话.所以要通过一个有公网地址的(服务器)中转一下.
    A 想和B通话.就发个信息给S要它中转下.S收到信息后.把A的IP地址与端口告诉B.B根据这个信息向A发个信息.
    由于时延.可以在A向S发个请求信息后.有个时延.然后再向B发信息.大约是这样..希望不会再记错.
      

  6.   

    这种情况通常用异步方法,发送命令后,等待回应,
    BeginReceive,不需要关心时间的延迟,应为你根本不知道
    数据会什么时候反应过来,因为Server可能会处理很多客户端
    你的数据在Server上可能需要排队,
      

  7.   

    参考QQ的协议A、B是两个点,S是目录服务器,
    A、B登录后均要向S报告自己的位置和端口,
    S还要定期对登录的用户点名,以便知道还在不在线。
    S判断A、B是不是都在线,如果都在线则通知他们自己去P2P,否则暂存在线的一方发来的消息,等另一方登录后发给他
      

  8.   

    参考QQ的协议A、B是两个点,S是目录服务器,
    A、B登录后均要向S报告自己的位置和端口,
    S还要定期对登录的用户点名,以便知道还在不在线。
    S判断A、B是不是都在线,如果都在线则通知他们自己去P2P,否则暂存在线的一方发来的消息,等另一方登录后发给他
    问题是路由不像我们自己的电脑分配端口自己可以知道,这里每次分配的端口只有通过S知道了,但是S只知道这次通讯的端口,怎么知道A准备跟B通讯的端口呢,又重新分配呢一个呀。总不能一个一个的试吧(也就是我上面提到的试着连接后续的10个端口看是否能连接上)。
      

  9.   

    大错特错,应该是这样的。
    A与B都要连接服务器C。
    A与B通信。那么A首先要向B发出一个连接,这时候NAT会记录下这个向B去的IP端口,当然了,到B会被阻止,但是在A这边会保存在NAT列表里一段时间。现在才是把A连向B出去那个地址发给C,由C发给B,这样B才可以A建立通信。
      

  10.   

    大错特错,应该是这样的。
    A与B都要连接服务器C。
    A与B通信。那么A首先要向B发出一个连接,这时候NAT会记录下这个向B去的IP端口,当然了,到B会被阻止,但是在A这边会保存在NAT列表里一段时间。现在才是把A连向B出去那个地址发给C,由C发给B,这样B才可以A建立通信。A与B通信。那么A首先要向B发出一个连接(问题是A向B的什么端口发,目前唯一能知道的是B跟C通讯的路由端口,不会是B跟C通讯的端口吧,这个时候B的路由路由绝对会阻止A的连接,确实A的路由有记录,但记录的是A连接B的一个与C连接的端口,这个时候如果你能保证B能用B跟C通讯的端口发信息给A就没有如何问题,但实际你拿什么保证路由器会一定把那个跟C的端口给你用??)
      

  11.   

    C 202。103。1。123:8000A---C   192.168.0.1:4000
    NAT A 记录  202.103.2.123:60000---202.103.1.123:8000B---C   192.168.1.1:4000
    NAT B 记录  202.103.3.123:30000---202.103.1.123:8000照wmhnq() 的说法
    A 向B 发连接
    A---B   202.103.1.123:8000
    NAT A 记录  202.103.2.123:?(不确定)---202.103.1.123:8000(这边阻止呢)
    A也得不到NAT A的202.103.2.123:?(不确定)怎么告诉C,它自己只知道开了一个192.168.0.1:4001去连接202.103.1.123:8000失败了。
      

  12.   

    上面写错了C 202.103.1.123:8000A---C   192.168.0.1:4000
    NAT A 记录  202.103.2.123:60000---202.103.1.123:8000B---C   192.168.1.1:4000
    NAT B 记录  202.103.3.123:30000---202.103.1.123:8000照wmhnq() 的说法
    A 向B 发连接
    A---B   202.103.3.123:30000
    NAT A 记录  202.103.2.123:?(不确定)---202.103.3.123:30000(这边阻止呢)
    A也得不到NAT A的202.103.2.123:?(不确定)怎么告诉C,它自己只知道开了一个192.168.0.1:4001去连接202.103.3.123:30000失败了。
      

  13.   

    你凭什么说失败。
    A与B已经连上服务器C。
    现在A与B想通信,
    A开始向B发出连接,这个时候通知服务器让B也连向A,双方的NAT列表都有彼此了。那么就可以连通了。
      

  14.   

    600分帮你解决该问题,给我发站内短信,MSN上吹。
      

  15.   

    http://midcom-p2p.sourceforge.net/draft-ford-midcom-p2p-01.txt
      

  16.   

    你凭什么说失败。
    A与B已经连上服务器C。
    现在A与B想通信,
    A开始向B发出连接,这个时候通知服务器让B也连向A,双方的NAT列表都有彼此了。那么就可以连通了。
    ----------------
    A B 已经连接上C 只能得到 A B 局域网ip和端口 和AB 所占用的 各自路由器 ip和端口 对吧。
    A开始向B发出连接,这个时候通知服务器让B也连向A,双方的NAT列表都有彼此了。那么就可以连通了,这一步就有问题了,A向B发的连接是什么?我想唯一能知道的就是B占用路由的IP和端口,但是却得不到现在A重新占用路由器A的新开端口了。如果A的路由器和B的路由器始终用相同的端口来向其它地址发信息就没有问题了。但问题是它会继续分配新的端口。而这个新的端口A自己的不到,B这个时候又链不上,当然就得不到。
      

  17.   


    http://midcom-p2p.sourceforge.net/draft-ford-midcom-p2p-01.txt
    里我看不懂,大概说得就是这个意思Ford, Srisuresh & Kegel                                        [Page 15]

    Internet-Draft     P2P applications across middleboxes      October 2003
       A-S 155.99.25.11:62000                        B-S 138.76.29.7:31000
                  |                                             |
                  |                                             |
               Client A                                      Client B
            10.0.0.1:1234                                 10.1.1.3:1234   NAT A has assigned its own UDP port 62000 to the communication
       session between A and S, and NAT B has assigned its port 31000 to the
       session between B and S.  By communicating through server S, A and B
       learn each other's public IP addresses and port numbers as observed
       by S.  Client A now starts sending UDP messages to port 31001 at
       address 138.76.29.7 (note the port number increment), and client B
       simultaneously starts sending messages to port 62001 at address
       155.99.25.11.  If NATs A and B assign port numbers to new sessions
       sequentially, and if not much time has passed since the A-S and B-S
       sessions were initiated, then a working bi-directional communication
       channel between A and B should result.  A's messages to B cause NAT A
       to open up a new session, to which NAT A will (hopefully) assign
       public port number 62001, because 62001 is next in sequence after the
       port number 62000 it previously assigned to the session between A and
       S.  Similarly, B's messages to A will cause NAT B to open a new
       session, to which it will (hopefully) assign port number 31001.  If
       both clients have correctly guessed the port numbers each NAT assigns
       to the new sessions, then a bi-directional UDP communication channel
       will have been established as shown below.                                  Server S
                                  18.181.0.31:1234
                                         |
                                         |
                  +----------------------+----------------------+
                  |                                             |
                NAT A                                         NAT B
       A-S 155.99.25.11:62000                        B-S 138.76.29.7:31000
       A-B 155.99.25.11:62001                        B-A 138.76.29.7:31001
                  |                                             |
                  |                                             |
               Client A                                      Client B
            10.0.0.1:1234                                 10.1.1.3:1234   Obviously there are many things that can cause this trick to fail.
       If the predicted port number at either NAT already happens to be in
       use by an unrelated session, then the NAT will skip over that port
       number and the connection attempt will fail.  If either NAT sometimes
       or always chooses port numbers non-sequentially, then the trick will
       fail.  If a different client behind NAT A (or B respectively) opens
       up a new outgoing UDP connection to any external destination after A
       (B) establishes its connection with S but before sending its firstFord, Srisuresh & Kegel                                        [Page 16]
      

  18.   

    用UDP打洞就可以了,QQ就是根据这原理
      

  19.   

    你他吗的,就不能自己领会一下吗,去试验一下吗,说的已经够他吗的清楚了。
    A与B已经连上服务器C。
    现在A与B想通信,
    A开始向B发出连接,连B的哪里,我靠,你B连到C是什么IP端口,就连什么。
    这个时候通知服务器让B也连向A,我靠,你A连到C是什么IP端口,就连什么。
    双方的NAT列表都有彼此了。
    那么就可以连通了。
      

  20.   

    我已经做这个东西.其实很简单,原理就是要知道对方的内网对应的外网的网络地址和端口.
    有四种方式可以实现:1:NAT/ALG 方式 NAT/ALG是支持VOIP NAT穿透的一种最简单的方式,但由于网络实际情况是已部署了大量的不支持此种特性的NAT/FW设备,因此,实际应用中,很难采用这种方式。2:MIDCOM 方式 3:STUN 方式 解决穿透NAT问题的另一思路是,私网中的VOIP终端通过某种机制预先得到出口NAT上的对外地址,然后在净载中所填写的地址信息直接填写出口NAT上的对外地址,而不是私网内终端的私有IP地址,这样净载中的内容在经过NAT时就无需被修改了,只需按普通NAT流程转换报文头的IP地址即可,净载中的 IP地址信息和报文头地址信息是一致的。STUN协议就是基于此思路来解决应用层地址的转换问题。TURN方式4:TURN方式解决NAT问题的思路与STUN相似,也是私网中的VOIP终端通过某种机制预先得公网上的服务地址(STUN方式得到的地址为出口NAT上外部地址,TURN方式得到地址为TURN Server上的公网地址),然后在报文净载中所要求的地址信息就直接填写该公网地址。
      

  21.   

    呵呵,上面的基础知识可能很多人都知道了,那么下面是关键的部分了。
        看看下面的情况:
        Server S1                                     Server S2
     18.181.0.31:1235                              138.76.29.7:1235
            |                                             |
            |                                             |
            +----------------------+----------------------+
                                   |
       ^  Session 1 (A-S1)  ^      |      ^  Session 2 (A-S2)  ^
       |  18.181.0.31:1235  |      |      |  138.76.29.7:1235  |
       v 155.99.25.11:62000 v      |      v 155.99.25.11:62000 v
                                   |
                                Cone NAT
                              155.99.25.11
                                   |
       ^  Session 1 (A-S1)  ^      |      ^  Session 2 (A-S2)  ^
       |  18.181.0.31:1235  |      |      |  138.76.29.7:1235  |
       v   10.0.0.1:1234    v      |      v   10.0.0.1:1234    v
                                   |
                                Client A
                             10.0.0.1:1234
        接上面的例子,如果Client A的原来那个Socket(绑定了1234端口的那个UDP Socket)又接着向另外一个Server S2发送了一个UDP包,那么这个UDP包在通过NAT时会怎么样呢?
        这时可能会有两种情况发生,一种是NAT再次创建一个Session,并且再次为这个Session分配一个端口号(比如:62001)。另外一种是NAT再次创建一个Session,但是不会新分配一个端口号,而是用原来分配的端口号62000。前一种NAT叫做Symmetric NAT,后一种叫做Cone NAT。我们期望我们的NAT是第二种,呵呵,如果你的NAT刚好是第一种,那么很可能会有很多P2P软件失灵。(可以庆幸的是,现在绝大多数的NAT属于后者,即Cone NAT)算了,我已经知道原因了,可能我的开发环境叫做Symmetric NAT 吧
    上面你们回答一直回避了一个问题,就是A 连 C 时 和 A 连 B 时 可能NAT A 用相同的端口而且不变的,但是有的时候它又换了一个新端口,而这点取决NAT 本身。A 或 B 都 不会能决定下次它用那个端口。
      

  22.   

    刚才测试了,好像可以不需要TCP但是如果用UDP就要每隔一段时间向服务器发送数据保证端口不被NAT取消,然而这个时间又有一个新的问题,不同硬件时间是不一样的,时间短了服务器是个问题,时间长了可能某些设备过期了。刚才测试好像45秒还没有过期。
      

  23.   

    我的神啊!如果你描述的内容是“载波监听,多路访问,冲突检测”的以太网世界
    ------------------------------
    物理:HUB,网线
    链路:MAC,ARP,交换机
    网络:IP,ICMP,IGMP,路由器
    传输:TCP,UDP
    会话:HTTP,SMTP,FTP,POP3
    表示:SOAP,SSL
    应用:WebService的Method
    -------------------------------
    这些老大们生活在不同的世界,
    对与交换机对话要用MAC地址与ARP协议
    与路由器对话要用IP封包协议
    机器间对话要用TCP,UDP,当然还有好多(Ping类的例外,他用ICMP)
      

  24.   

    A,B,启动时向S登记自已的信息..如是内网则是公网的ip地址加路由随机的端口号.
    ——————————————————————————————————————————
    不太相信。
      

  25.   

    哦 记得 好久以前 有 C#代码的版本啊 并且 下来 测试过 好用的 只是 它实现的很简单 没有完善,发几次消息就死掉了. 但功能是 正确的 两个内网 可以正常通讯 代码 可以 去 codeproject 找找 如果 找不到 留个email 我发给你一份
      

  26.   

    代码嘛 为非就是 能run起来 不能run起来 商用的 无非 也就是 更强壮 更稳定 而已  怎么还分真假啊难道 商用的就不是个人想出来的了
      

  27.   

    我测试过网上文章、论坛、群中好几个好多人下载的代码,结果证明都是假的,经不起测试程序的测试。如果你仅仅在乎是否“知道”所谓的“穿透NAT原理”的文章,那么不做稍微正规一点的测试也是可以理解的。当然有可以用的代码,但是根本不是那么简单。
      

  28.   

    如果只考虑理想环境只是要尝试穿透nat,那么所谓的“穿透NAT原理”的文章还是有点作用的,但是绝对达不达理想效果,我以前研究时测试过,基本上没有通过,要不就只通过一方.后来我根据理论添加了点东西,比如心跳包(大概1-2分钟发一次吧),然后又添加了双向"打洞"才搞定,不过这样也这是在理想环境真正的系统还要考虑很多很多东西,复杂多了
      

  29.   

    几百年前的东西了还在讨论,UDP打洞(参考开院项目STUN),不透非对称NAT... 现在也有了TCP打洞(参考开院项目XSTUNT),
      

  30.   

    晕死……楼主听我说吧:1. 都说 NAT,其实这里具体的应该叫 NAPT,就是 Network Address Port Translation,把本机的端口在路由上做映射。如果 A、B 两个路由都不支持端口映射,那你就死心吧,他们不可能连通的,必须通过 Server 中转。2. 至于有人说,A 和 Server 用什么端口联,就让 B 连 A 的这个端口,更晕。A 连 Server,是不需要提供 A 的端口的,只需要连接到 Server 的指定端口。3. 如果你用的是固定端口,比如 8000,那么内网内两台同样的电脑 A1、A2,你怎么区分它们呢?反正路由器只有一个,IP 只有一个。所以,你需要动态指定端口。早期的许多网络程序,端口都是固定的,这样内网内有两个用户的话,就没法用了。4. TCP 和 UDP 用法一样。简单来说,区别就是 TCP 可靠性高,UDP 效率高。5. 你还可以考虑支持路由器的 UPnP 功能,不过可惜并不是所有路由器都支持。WinXP 自带了支持 UPnP 的功能,用这样的路由器,在组件中安装上相关支持(默认没有安装),然后你的程序再考虑支持 UPnP,就简单多了。比如咱们熟知的 BitComet 就是这样做的。不过,目前只有 WinXP 才支持路由器的 UPnP,其他系统不支持,只能让用户手工在路由器上映射。6. 你还要考虑支持 WinXP 的防火墙,否则这个默认的防火墙会把你搞得非常郁闷的。临时兴起,只想到了这么多。不常来 CSDN,祝你顺利解决问题。
      

  31.   

    你要考虑一下NAT的模式问题。不同的NAT模式有不同的处理方式。SO....
      

  32.   

    学习CSDN论坛浏览器:浏览、发帖、回复、结贴自动平均给分,下载地址:http://CoolSlob.ys168.com
      

  33.   

    哈哈,好怀念啊,一年前也想用JAVA编个P2P的软件,遇到了同样的问题,看了一个多星期的资料,后来在操作系统课上,在WINDOWS2003的帮助里找到关于UDP穿透的解决方案,那里写的很容易理解。感谢MS
      

  34.   

    去网上Google去,关键字收NAT;
    UDP打洞,关键就是UDP洞点对点,单向。
    所以嘛,A想揍扁B,不能随便去揍,B得先对A说你放马过来,A才能过来揍他。
    那么B怎么知道A要去揍他呢?哦。A请S转告B:我要揍你!