最近在研究p2p,通过网上的例子也实现了udp方式的穿透。
同时也在网上看到UPnP也可以实现NAT的穿透,但是还不了解其原理。
刚刚在配置路由器的时候,发现Baidu Hi在路由器的UPnP列表中存在端口映射,不知道这个是否是用来NAT穿透的?了解UPnP的兄弟谈谈看法 :)

解决方案 »

  1.   

    正确。UPNP提供了这种能力:使得内网的机器自动被映射到外网的固定协议和端口,这样内网机器相当于不再在NAT里面,而是直接公开到公网上了,此时远程机器可以不通过服务器协调而直连到你的内网机器上。所以如果使用了UPNP,TCP协议也能做到NAT穿透,并且无需任何中介服务器
      

  2.   

    哦晓得了,类似于配置DMZ吧。被映射的是公网IP吗,软件里面如何使用UPNP呢,请不吝赐教。
      

  3.   


    这下问题又来了:NAT是为解决IP地址不足而引入的;UPNP可好,反NAT之道而行之。试问:假如在一个公共网关下有多个UPNP,它们都能够保证这种映射关系成功吗?又或是在这之间又虚拟了一个NAT出来解决冲突问题?
      

  4.   

    UPNP首先是NAT设备提供的,内网机器的操作系统中需要支持UPNP服务(XP下该服务是可选服务,可能没有启动),当服务启动时,机器会扫描到NAT设备是否支持UPNP,如果支持就能提供正常服务。应用程序应该使用UPNP提供的服务来申请固定的端口映射,如果NAT设备发现该端口可用,则会创建端口映射表,如果端口已被占用,则会返回失败,但你可以尝试向NAT设备请求一个随机端口,NAT设备会寻找一个空闲的端口返回。简单一点说:UPNP协议使得内网机器可以通过程序方式来动态修改NAT设备的端口映射表。
      

  5.   

    UPNP是基于TCP/IP实现的另一种协议,大部分路由器支持这种UPNP映射。好像并不是暴露在公网上,只是做了穿越NAT的一种映射。
      

  6.   

    资料?当然有,看看SSDP和SOAP协议就行了,要会XML哦!我有个小工程,大家想要么?我上传到CSDN好不好啊??
      

  7.   

    如果本地网络可以使用UPNP,那么应该优先使用UPNP
    如果不支持,再使用UDP打洞这样的穿透
    效果是一样的
      

  8.   

    开源的电驴上就有 verycd emule#pragma once
    #include <WinSock2.h>
    #include "UPnpError.h"class CUPnpNat
    {
    public:
    CUPnpNat(void);
    ~CUPnpNat(void); enum {SEARCH_TIMEOUT_MS = 15000,
    DEF_ACTION_TIMEOUT_MS = 9000}; void SetBindAddress(LPCTSTR lpszBindAddress){m_strBindAddress = lpszBindAddress;}
    void SetActionTimeout(int iActionTimeoutMs = DEF_ACTION_TIMEOUT_MS){m_iActionTimeoutMs = iActionTimeoutMs;}
    int  GetActionTimeout(){return m_iActionTimeoutMs;}
    HRESULT SearchDevice(BOOL bUseDefaultGateway = TRUE);
    HRESULT AddPortMapping(LPCTSTR lpszRemoteHost,
    USHORT usExternalPort, LPCTSTR lpszPortMappingProtocol,
    USHORT usInternalPort, LPCTSTR lpszInternalClient,
    LPCTSTR lpszPortMappingDescription = NULL,
    BOOL bPortMappingEnabled = TRUE,
    ULONG ulPortMappingLeaseDuration = 0); HRESULT DeletePortMapping(LPCTSTR lpszRemoteHost,
    USHORT usExternalPort,
    LPCTSTR lpszPortMappingProtocol);
    HRESULT GetSpecificPortMappingEntry(LPCTSTR lpszRemoteHost, //[in]
    USHORT usExternalPort, //[in]
    LPCTSTR lpszPortMappingProtocol, //[in]
    USHORT *pusInternalPort, //[out]
    CString *pstrInternalClient, //[out]
    bool *pbEnable, //[out]
    CString *pstrDescription, //[out]
    ULONG *pulPortMappingLeaseDuration); //[out]
    HRESULT GetGenericPortMappingEntry(USHORT usIndex, //[in]
    CString *pstrRemoteHost, //[out]
    USHORT *pusExternalPort, //[out]
    CString *pstrProtocol, //[out]
    USHORT *pusInternalPort, //[out]
    CString *pstrInternalClient, //[out]
    bool *pbEnable, //[out]
    CString *pstrDescription); //[out] DWORD GetLastActionErrorCode(){return m_dwLastErrorCode;}protected:
    void SetLastActionErrorCode(DWORD dwLastErrorCode){m_dwLastErrorCode = dwLastErrorCode;} HRESULT SOAP_action(CString addr, UINT16 port, const CString request, CString &response);
    int SSDP_sendRequest(SOCKET s, UINT32 ip, UINT16 port, const CString& request); bool InternalSearch(int version, BOOL bUseDefaultGateway = FALSE);
    bool GetDescription();
    CString GetProperty(const CString& name, CString& response);
    bool isComplete() const { return !m_controlurl.IsEmpty(); }
    bool Valid()const{return (/*!m_name.IsEmpty()&&*/!m_description.IsEmpty());} HRESULT InvokeCommand(const CString& name, const CString& args, CString &strResponse); static BOOL IsLengthedHttpPacketComplete(const char *packet, int len);
    protected:
    CString m_strBindAddress;
    int m_iActionTimeoutMs; DWORD m_dwLastErrorCode; BOOL m_isSearched; int m_version;
    CString m_devicename;
    CString m_name;
    CString m_description;
    CString m_baseurl;
    CString m_controlurl;
    CString m_friendlyname;
    CString m_modelname;};
      

  9.   

    #include "StdAfx.h"
    #include ".\upnpnat.h"
    #include "IpHlpApi.h"
    #pragma comment (lib, "IpHlpApi.lib")
    //#define NUMBEROFDEVICES 2
    //static const CString s_devices[][2] = {{_T("WANIPConnection"), _T("service")},
    // {_T("WANPPPConnection"), _T("service")}};#define UPNPPORTMAP0   _T("WANIPConnection")
    #define UPNPPORTMAP1   _T("WANPPPConnection")
    static const ULONG UPNPADDR = 0xFAFFFFEF;
    static const int UPNPPORT = 1900;
    static const CString URNPREFIX = _T("urn:schemas-upnp-org:");//////////////////////////////////////////////////////////////////////////
    //extern const CString getString(int i);
    extern const CString GetArgString(const CString& name, const CString& value);
    extern const CString GetArgString(const CString& name, int value);
    extern bool parseHTTPResponse(const CString& response, CString& result);
    extern const CString getProperty(const CString& all, const CString& name);const CString getString(int i)
    {
    CString s; s.Format(_T("%d"), i); return s;
    }const CString GetArgString(const CString& name, const CString& value)
    {
    return _T("<") + name + _T(">") + value + _T("</") + name + _T(">");
    }const CString GetArgString(const CString& name, int value)
    {
    return _T("<") + name + _T(">") + getString(value) + _T("</") + name + _T(">");
    }bool parseHTTPResponse(const CString& response, CString& result)
    {
    int pos = 0; CString status = response.Tokenize(_T("\r\n"), pos); result = response;
    result.Delete(0, pos); pos = 0;
    status.Tokenize(_T(" "), pos);
    status = status.Tokenize(_T(" "), pos);
    if (status.IsEmpty() || status[0]!='2') return false;
    return true;
    }