项目中的一个c/s应用,获得客户机的公网ip地址。使用的udp通讯,现在在大多数网络情况下都能正常通讯,但是有些nat下的客户机不能收到包!代码:
客户端:发送一个登陆包,然后阻塞着等服务器的应答sendto(m_hUSock, (const char*)&H2SLogPct, sizeof(H2SLogPct), 0, (sockaddr*)&m_ServerAddr, sizeof(sockaddr_in));int nRecv = recvfrom(m_hUSock, (char *)&S2HRpyLogonPct, sizeof(S2HRpyLogonPct), 0, (LPSOCKADDR)&m_RecvAddr, &m_nAddrLen);
服务器端:
int nRecv = recvfrom(m_hUSock, (char *)zRcvBuf, sizeof(zRcvBuf), 0, (LPSOCKADDR)&addrhost, &nAddrLen);CRpyNorPct RpyNorPct;sendto(m_hSock, (char*)&RpyNorPct, sizeof(RpyNorPct), 0, (sockaddr*)&addrhost, sizeof(sockaddr_in));
服务器将按照接收的地址发送回去,部分路由后的客户端不能接收到主机的回复包,这是为什么?

解决方案 »

  1.   

    不是所有的nat都能穿透的,前几天不是有位牛人发帖号称他的程序能穿透所有net吗,可以向他请教
      

  2.   

    其实我的问题说百了,就是nat后的一个主机使用udp向服务器通讯,而服务器根据接受的地址回复一个应答包。而现在实际应用中遇到不少nat后的主机不能接收到这个应答包。而我去客户那也测试和调试了,并不是所有udp包均被拦截,至少能跑qq,而且抓包后确认其是用udp通讯的
      

  3.   

    其实就是外网通过udp给内网的机器发送消息,但是必须要内网的机器向外网的机器的udp的端口发送注册消息,外网的机器通过recvfrom能得到ip和port,然后向这个ip和port发送数据,内网的机器可以接受到   
    我现在实际就是这个example:   
      内网机器A,外网机器B,外网机器绑定端口3000,   
      1.A向B的3000端口发送消息注册   
      2.B通过recvfrom得到ip,port   
      3.B向得到的ip和port发送数据   
      4.A能接收到B发送的数据   
     而我在别人的帖子中看到的方式有:   
      内网机器A,外网机器B,内网机器绑定端口2000,外网机器绑定端口3000,   
      1.A向B的3000端口发送消息注册   
      2.B通过recvfrom得到ip,port   
      3.B向得到的ip和port发送数据   
      4.A在2000端口上能接收到B发送的数据   
     唯一区别就是我的例子没有在内网绑定端口,难道问题就是出在这里?
      

  4.   

    服务器端发送的时候,要保证按照接收的那个端口发送数据。例如:你服务器的监听端口是:8080那么,你的服务器给客户端发送报文的时候,也一定用8080端口,别新开一个专门发送的socket。你的代码中,服务器端发送socket和监听socket好像不是一个。原因:
    很多NAT设备是基于五元组的,例如: A--NAT---Server(固定IP).经过NAT之后是这样的:(IP1:Port1 --- IP2:8080) 
    IP1是NAT之后的IP、Port1是NAT之后的Port。IP2、8080是你固定IP的端口和IP。 如果你新开一个socket给A回应,IP是这样的: 
    IP2:PORT2----IP1:Port1   IP2是系统分配的一个端口,或者你bind的端口。但是,很多NAT设备发现PORT2不是由A发出去的端口,因此是不让进入,这种属于一种严格的地址转换方式,现在大部分NAT设备都是这样的。 这个五元组就类似一个“洞”,不是很多NAT穿越也叫在路由器上“打洞”就是这个道理。
      

  5.   

    squiffy 谢谢!的确我使用的不是一个端口。服务端的程序使用的是多线程分发机制,一个socket接收网络包,然后立即分发到下层的线程处理包。按照你说的,“严格的地址转换方式”,那也就是说我的处理线程需要都去绑定同一个端口号? 而真这样的话还需要设置端口复用。 而且如果按照严格的地址转换方式,p2p的打洞方式也会有问题,如lan-lan的方式?
      

  6.   

    Jasonshengxi:
    是这样的,严格来说,LAN--LAN方式,如果两个LAN都处于私网,如果没有一个中介转发的话,成功率会很低。因此,你看QQ,很多时候都是处于一种“服务器转发模式”,这种模式其实就是两个网吧之间的PC通信。类似你程序设计的方式,我觉得应该对下面的线程再聚合一下,意思就是每个线程处理完了一个,把发送报文交给一个独立的线程或者socket接收的那个线程做发送处理。让你的socket工作于“全双工模式”。
      

  7.   

    To squiffy: 明白你的意思了。的确在使用严格地址转换方式的nat下,我原有的设计,client便会收不到应答包。而client如果只是一个socket,bind或不bind应该都是一样的(见我之前说)。一直以来,我都忽视了server端的端口也需要这样和client端对应但若真只能使用接收的这个socket来发送应答包,在有大量访问时,这个效率是很大问题.是否有其他方法呢?
      

  8.   

    To squiffy: 
    的确处理完后聚合,使用另一个线程来发送,socket采用“全双工模式”是个很好的办法!
    我下周去客户那儿做这个测试,谢谢!