CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
不看会后悔的Windows XP之经验谈 简单快捷DIY实用家庭影院
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  VC/MFC >  网络编程

关于p2p中,穿透nat的不稳定性问题

楼主lybid2002(随风)2006-03-01 09:52:53 在 VC/MFC / 网络编程 提问

原来是贴在dfw那的一个帖子。分不够可以加。谢谢  
  网络上有很多关于穿透NAT的文章,很多是关于UDP打洞的。  
  我下载了一位前辈的实现这个原理代码,可是很奇怪的是:  
  相同的网络环境,有时候可以通,有时候又不通。客户端代码片断如下:  
  发送消息:  
  function   SendMessageTo(pSendName:   pchar;   pInfo:   Pointer;   size:   integer):   BOOL;  
  begin  
          for   i   :=   0   to   MAXRETRY   do  
          begin  
                  RecvedACK   :=   false;  
                  remoteAddr.sin_addr.S_addr   :=   htonl(UserIP);  
                  remoteAddr.sin_family   :=   AF_INET;  
                  remoteAddr.sin_port   :=   htons(UserPort);  
                  MessageHead.ord   :=   oP2PMESSAGE;  
                  MessageHead.iStringLen   :=   size;  
                  strcopy(MessageHead.Sender,   userName);  
                  err   :=   sendto(sock,   MessageHead,   SizeOf(MessageHead),   0,   remoteAddr,   SizeOf(remoteAddr));  
                  sendto(sock,   pInfo^,   MessageHead.iStringLen,   0,   remoteAddr,   SizeOf(remoteAddr));  
                  //   等待接收线程将此标记修改  
                  for   j   :=   0   to   10   do  
                  begin  
                          if   (RecvedACK)   then  
                          begin  
                                  result   :=   True;  
                                  exit;  
                          end   else  
                                  Sleep(300);  
                  end;   //for  
                  //   没有接收到目标主机的回应,认为目标主机的端口映射没有  
                  //   打开,那么发送请求信息给服务器,要服务器告诉目标主机  
                  //   打开映射端口(UDP打洞)  
                  serverAddr.sin_addr.S_addr   :=   Inet_addr(svrIP);  
                  serverAddr.sin_family   :=   AF_INET;  
                  serverAddr.sin_port   :=   htons(SERVER_PORT);  
                  transMessage.ord   :=   oP2PTRANS;  
                  strcopy(transMessage.msg.translatemessage.userName,   pSendName);  
                  sendto(sock,   transMessage,   SizeOf(transMessage),   0,   serverAddr,   SizeOf(serverAddr));  
                  Sleep(500);   //   等待对方先发送信息。  
          end;   //for  
  end;  
  接收线程代码  
  while   True   do  
          begin  
                  err   :=   recvfrom(sock,   recvbuf,   SizeOf(recvbuf),   0,   remoteAddr,   addrLen);  
                  if   err   <=   0   then   continue;  
                  pData   :=   nil;  
                  recvtype   :=   -100;  
                  case   recvbuf.ord   of  
                          oP2PMESSAGE:  
                                  begin  
                                          getmem(pInfo,   recvbuf.iStringLen);  
                                          err   :=   recvfrom(sock,   pInfo^,   recvbuf.iStringLen,   0,   remoteAddr,   addrLen);  
                                          if   err   <=   0   then   continue;  
                                          pData   :=   pInfo;  
                                          recvtype   :=   1;  
                                          recvsize   :=   recvbuf.iStringLen;  
                                          sendbuf.ord   :=   oP2PMESSAGEACK;  
                                          sendto(sock,   sendbuf,   SizeOf(sendbuf),   0,   remoteAddr,   addrLen);  
                                          //freemem(pInfo);  
                                          //break;  
                                  end;   //oP2PMESSAGE接收到P2P的消息  
                          oP2PSOMEONEWANTTOCALLYOU://收到服务器要求向某个客户端打洞的消息  
                                  begin  
                                          remoteAddr.sin_addr.S_addr   :=   htonl(recvbuf.iStringLen);  
                                          remoteAddr.sin_family   :=   AF_INET;  
                                          remoteAddr.sin_port   :=   htons(recvbuf.port);  
                                          sendbuf.ord   :=   oP2PTRASH;  
                                          sendto(sock,   sendbuf,   SizeOf(sendbuf),   0,   remoteAddr,   SizeOf(remoteAddr));  
                                          //break;  
                                  end;   //接收到打洞命令,向指定的IP地址打洞  
                          oP2PMESSAGEACK:  
                                  begin  
                                          RecvedACK   :=   True;  
                                  end;   //   发送消息的应答  
                                ...........  
                                ..............  
  还有一个问题:有资料上说,为了保持NAT给应用程序分配的UDP端口不被回收,应该让应用程序定时地向NAT给自己分配的地址和端口发包。  
  例如:CA的LAN地址是192.168.0.3:1234   经过NAT后变成218.66.101.35:8666,那么CA应该定时向218.66.101.35:8666发送UDP包来保持这个  
  8666的端口。但是我按照这样做只好,发现CA并不能收到这个包  
          while   true   do  
          begin  
                  err   :=   sendto(sock,   msg,   SizeOf(msg),   0,   remoteAddr,   addr);//跟踪发现err>0  
                  Sleep(3000);  
          end;    
  有没有什么工具可以知道NAT是否抛弃了那些UDP包                  
  请大侠指教,这会是什么问题。我已经倾我所有的分数了            
   
   
  来自:Roseking,   时间:2006-2-28   9:15:32,   ID:3366395  
  不太明白你的思路,   不过有一个您似乎弄错了  
    sendto   成功时返回发出的字节数,   失败返回-1      
   
   
  来自:jamjar,   时间:2006-2-28   9:18:05,   ID:3366400  
  楼上的,我的意思就是我的sendto成功了,但是收不到这个消息      
   
   
  来自:Roseking,   时间:2006-2-28   9:19:44,   ID:3366404  
  UDP本来就是不可靠的,   sendto成功了,对方也可能没有收到这个数据包      
   
   
  来自:jamjar,   时间:2006-2-28   9:21:46,   ID:3366405  
  我是一个循环来发,难道都收不到吗。  
   
       
   
   
  来自:jamjar,   时间:2006-2-28   9:30:54,   ID:3366412  
  基本思路是这样的  
  1:客户端(A)直接向对方(B)的目的地址和端口发送包。  
  2:如果收到B的回答(RecvdASK=true),就算成功了。  
  3:如果没有收到B的回答(recvedASK=false),那么就给服务器发个请求包。  
      这个包里有B的信息。服务器给B发包,要求B给A发一个包(也就是打洞)。  
      按照原理,B的NAT上将打开一个通道,让A发送的包进来。  
  4:此时A发的包,B就能收到了      
   
   
  来自:41426277,   时间:2006-2-28   9:36:55,   ID:3366422  
  jamjar,   真是太谢谢你的提示.      
   
   
  来自:jamjar,   时间:2006-2-28   9:46:22,   ID:3366437  
  这个是服务端出来打洞的代码  
                          oP2PTRANS:  
                                  begin  
                                          for   i   :=   0   to   clientList.Count   -   1   do  
                                          begin  
                                                  pUserListNode   :=   clientList.Items[i];  
                                                  if   strcomp(pUserListNode^.UserName,   Buf.msg.translatemessage.UserName)   =   0   then   break;  
                                          end;   //for  
                                          remoteAddr.sin_family   :=   AF_INET;  
                                          remoteAddr.sin_port   :=   htons(pUserListNode^.port);  
                                          remoteAddr.sin_addr.s_addr   :=   htonl(pUserListNode^.ip);  
                                          transMessage.ord   :=   oP2PSOMEONEWANTTOCALLYOU;  
                                          transMessage.iStringLen   :=   ntohl(SenderAddr.sin_addr.s_addr);  
                                          transMessage.port   :=   ntohs(SenderAddr.sin_port);  
                                          sendto(sock,   transMessage,   sizeof(transMessage),   0,   remoteAddr,   addrLen);  
                                          //break;  
                                  end;   //oP2PTRANS   //   某个客户希望服务端向另外一个客户发送一个打洞消息      
   
   
  来自:jamjar,   时间:2006-2-28   10:06:51,   ID:3366465  
  运行后,出现的情况是  
  如果A向B发送消息,  
  那么B可以收到服务器发来的要求B向A打洞的消息,但是无法收到A的消息      
   
   
  来自:netfun2000,   时间:2006-2-28   12:22:24,   ID:3366692  
  帮你顶,关注中....^_^  
       
   
   
  来自:bbscom,   时间:2006-2-28   12:35:22,   ID:3366711  
  打洞裡有漏洞      
   
   
  来自:jamjar,   时间:2006-2-28   15:31:46,   ID:3366996  
  楼上说的是啥意思,麻烦说明白,心里急啊      
  问题点数:100、回复次数:7Top

1 楼nuaawenlin(飘人)回复于 2006-03-01 10:05:55 得分 30

从你的代码没有看出,B和A之间没有相互发送Session的消息  
   
  当接收到服务器的打洞消息后,A和B都要向各自的网关发送一个Session,告诉它允许对方的UDP数据进入内网Top

2 楼lybid2002(随风)回复于 2006-03-01 10:26:45 得分 0

to   nuaawenlin(飘人):  
      代码只贴出了片断,A和B都要向各自的网关发送一个Session,告诉它允许对方的UDP数据进入内网,这个是有的。否则也不会有的时候发送成功了。  
  如果需要的话,把代码都贴出来。Top

3 楼myth_2002(myth)回复于 2006-03-01 10:38:53 得分 40

俺就是那个jamjar,还是我来说吧  
  假如A要向B发消息  
                remoteAddr.sin_addr.S_addr   :=   htonl(UserIP);//这里就是B的外网地址  
                  remoteAddr.sin_family   :=   AF_INET;  
                  remoteAddr.sin_port   :=   htons(UserPort);//这里就是B的外网端口  
                  MessageHead.ord   :=   oP2PMESSAGE;  
                  MessageHead.iStringLen   :=   size;  
                  strcopy(MessageHead.Sender,   userName);  
                  err   :=   sendto(sock,   MessageHead,   SizeOf(MessageHead),   0,   remoteAddr,   SizeOf(remoteAddr));//向B的外网地址发消息。  
                  sendto(sock,   pInfo^,   MessageHead.iStringLen,   0,   remoteAddr,   SizeOf(remoteAddr));  
  如果不成功,那么就请求服务器给B发消息  
        serverAddr.sin_addr.S_addr   :=   Inet_addr(svrIP);  
                  serverAddr.sin_family   :=   AF_INET;  
                  serverAddr.sin_port   :=   htons(SERVER_PORT);  
                  transMessage.ord   :=   oP2PTRANS;  
                  strcopy(transMessage.msg.translatemessage.userName,   pSendName);  
                  sendto(sock,   transMessage,   SizeOf(transMessage),   0,   serverAddr,   SizeOf(serverAddr));  
                  Sleep(500);   //   等待对方先发送信息。  
   
  B收到服务器发来的消息后:  
                        oP2PSOMEONEWANTTOCALLYOU://收到服务器要求向某个客户端打洞的消息  
                                  begin  
                                          remoteAddr.sin_addr.S_addr   :=   htonl(recvbuf.iStringLen);//这里是A的外网地址  
                                          remoteAddr.sin_family   :=   AF_INET;  
                                          remoteAddr.sin_port   :=   htons(recvbuf.port);//A的外网端口  
                                          sendbuf.ord   :=   oP2PTRASH;  
                                          sendto(sock,   sendbuf,   SizeOf(sendbuf),   0,   remoteAddr,   SizeOf(remoteAddr));//向A的外网地址发消息  
                                          //break;  
                                  end;   //接收到打洞命令,向指定的IP地址打洞  
   
   
   
  Top

4 楼alen_ghl(东方求*)回复于 2006-03-01 10:41:10 得分 10

是不是session的时间有效性导致的?Top

5 楼myth_2002(myth)回复于 2006-03-01 11:22:08 得分 10

请alen_ghl详细说一下,如何保持sessionTop

6 楼returnnull(南斗)回复于 2006-03-01 18:10:16 得分 10

session   大概只有数十秒的时效    
  所以要做心跳包保活Top

7 楼echomo123(无语)回复于 2006-03-15 14:18:42 得分 0

关注Top

相关问题

  • 关于p2p中,穿透nat的不稳定性问题
  • skype是如何穿透NAT的?
  • 【P2P专题讨论】之 NAT穿透
  • 【P2P专题讨论】之 NAT穿透
  • dataReader的稳定性
  • 调查 WinXP 的稳定性
  • weblogic稳定性问题
  • P2P之UDP穿透NAT的问题,请高手帮帮忙
  • tcp穿透nat: windows xp下如何发送一个syn包?
  • 我问个简单问题,TCP能象UDP那样实现穿透NAT吗?

关键词

  • p2p
  • 端口
  • 服务器
  • 代码
  • 消息
  • remoteaddr
  • messagehead
  • jamjar
  • transmessage
  • serveraddr

得分解答快速导航

  • 帖主:lybid2002
  • nuaawenlin
  • myth_2002
  • alen_ghl
  • myth_2002
  • returnnull

相关链接

  • Visual C++类图书
  • Visual C++类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo