乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      不同局域網(wǎng)內(nèi)經(jīng)Internet的P2P通信技術(shù)總結(jié) - P2P天空

       hitemplar 2005-09-27

      以下將要用到一個(gè)叫做NAT的重要名詞,先做點(diǎn)解釋。

      NAT是Net Address Translation(網(wǎng)絡(luò)地址轉(zhuǎn)換)的簡(jiǎn)稱,就是說(shuō),局域網(wǎng)通??恳粋€(gè)具有公網(wǎng)IP的代理網(wǎng)關(guān)服務(wù)器連到Internet共享上網(wǎng)。局域網(wǎng)內(nèi)的機(jī)器并不具備公網(wǎng)IP地址,它只有內(nèi)網(wǎng)地址,假設(shè)它要和Internet上的HTTP服務(wù)器通信,代理網(wǎng)關(guān)便會(huì)新建一個(gè)端口來(lái)和這個(gè)網(wǎng)內(nèi)機(jī)器關(guān)聯(lián),并通過(guò)這個(gè)端口來(lái)和HTTP服務(wù)器交換數(shù)據(jù)。最終,網(wǎng)內(nèi)機(jī)器->代理網(wǎng)關(guān)->HTTP服務(wù)器,在一個(gè)會(huì)話期間,各自的端口保持了映射關(guān)系,特別是代理網(wǎng)關(guān)和網(wǎng)內(nèi)機(jī)器的端口映射,使得代理網(wǎng)關(guān)不會(huì)把接收到的數(shù)據(jù)向網(wǎng)內(nèi)轉(zhuǎn)發(fā)時(shí),發(fā)錯(cuò)了機(jī)器。

      局域網(wǎng)內(nèi)的機(jī)器在網(wǎng)關(guān)處,就是靠NAT來(lái)映射端口并實(shí)現(xiàn)Internet連接,因此,NAT也直接被稱為“端口映射”。端口映射之后,在一個(gè)會(huì)話期間保持,對(duì)于TCP連接是直到連接斷開才銷毀,而對(duì)于UDP,卻存在一個(gè)不定的生存期,例如2秒。

      如果兩臺(tái)機(jī)器A和B,分別處于兩個(gè)局域網(wǎng)內(nèi),它們要通過(guò)Internet通信,這就是P2P(點(diǎn)到點(diǎn))連接通信。

      目前的Internet使用IPv4協(xié)議,采用32位IP地址,主要被用來(lái)進(jìn)行C/S形式的通信,需要共享的資源集中放于Internet服務(wù)器上。IPv4對(duì)于P2P分布式資源共享的支持,極不友好。首先,32位IP地址已經(jīng)不敷使用,公網(wǎng)IP地址日趨緊張,只能使用局域網(wǎng)共享公網(wǎng)IP的方式,局域網(wǎng)正是為了臨時(shí)應(yīng)對(duì)IP耗盡而出現(xiàn)的,長(zhǎng)遠(yuǎn)的解決辦法是研究IPv6。其次,分別處于兩個(gè)局域網(wǎng)內(nèi)的機(jī)器要通信,由于對(duì)方?jīng)]有公網(wǎng)IP,直接呼叫對(duì)方是不可能的,必須借助第三方“中介”(機(jī)器或者軟件)間接地連通,解決辦法下列幾種:

      第一:實(shí)現(xiàn)局域網(wǎng)內(nèi)的數(shù)據(jù)鏈路層協(xié)議,就是寫一個(gè)類似于TCP/IP的協(xié)議,由它來(lái)代替Windows系統(tǒng)里的TCP/IP協(xié)議,由它直接基于網(wǎng)卡硬件獲取數(shù)據(jù)。這是十分復(fù)雜的。

      第二:用Internet上的公網(wǎng)服務(wù)器中轉(zhuǎn)數(shù)據(jù),但對(duì)于大數(shù)據(jù)量的中轉(zhuǎn),顯然受到服務(wù)器和網(wǎng)絡(luò)的負(fù)載極限的限制。

      第三:依靠Internet上的公網(wǎng)服務(wù)器做“媒人”,將這兩臺(tái)分別處于不同局域網(wǎng)的機(jī)器相互介紹給對(duì)方,在它們建立連接之后,服務(wù)器即脫離關(guān)系。這種方式下,服務(wù)器把A的NAT端口映射關(guān)系告訴B,又把B的NAT端口映射關(guān)系告訴A,這樣AB相互知道對(duì)方的端口映射關(guān)系之后,就能建立連接。因?yàn)锳和B各自的端口映射關(guān)系是靠各自的代理網(wǎng)關(guān)動(dòng)態(tài)建立的,動(dòng)態(tài)建立的映射端口不得不告知對(duì)方。

      第四:上面的第三種辦法,也可以采用靜態(tài)端口映射方式,這樣就不需要中介服務(wù)器對(duì)A和B做介紹。在各方的代理網(wǎng)關(guān)上,可以在代理工具里將某個(gè)端口(如1350)和局域網(wǎng)內(nèi)的某臺(tái)機(jī)器(如內(nèi)網(wǎng)IP為200.200.200.100,端口1360)做好靜態(tài)映射,這樣,代理網(wǎng)關(guān)會(huì)自動(dòng)地將出入于1350端口的數(shù)據(jù)發(fā)往200.200.200.100的1360端口。當(dāng)然,通信之前,必須對(duì)對(duì)方的端口映射關(guān)系做配置。有多少臺(tái)網(wǎng)內(nèi)機(jī)器要通信,就得映射多少個(gè)不同的端口,同時(shí)在另一個(gè)局域網(wǎng)內(nèi)的機(jī)器就要做多少個(gè)配置。在局域網(wǎng)內(nèi)搭建HTTP、FTP等服務(wù)器就是通過(guò)靜態(tài)映射端口來(lái)實(shí)現(xiàn)的,這個(gè)端口一般不是HTTP、FTP的默認(rèn)80和23,所以對(duì)這類站點(diǎn)的訪問(wèn)往往會(huì)在URL里加上端口號(hào)。

      由此可見(jiàn),上述前兩種辦法在簡(jiǎn)單應(yīng)用中是不可取的,只有后兩種可行。它們又各有缺點(diǎn),第三種動(dòng)態(tài)映射端口,需要增加中間服務(wù)器,第四種靜態(tài)映射端口,在需要通信的各方機(jī)器很多的情況下,做手工端口映射和配置都是很繁瑣的,并且一方添加一臺(tái)機(jī)器,就需要在其余對(duì)方增加配置。

      采用動(dòng)態(tài)和靜態(tài)相結(jié)合的辦法是可以推想的,然而其可行性還必須經(jīng)過(guò)測(cè)試??梢赃@樣設(shè)計(jì),為了讓所有通信機(jī)器彼此知曉并定位。我們可以在局域網(wǎng)里,只對(duì)一臺(tái)機(jī)器在代理網(wǎng)關(guān)處做靜態(tài)端口映射,本局域網(wǎng)內(nèi)的機(jī)器都向它登記。而兩個(gè)局域網(wǎng)各自只做一項(xiàng)對(duì)對(duì)方的映射配置。兩個(gè)局域網(wǎng)之間,沒(méi)有靜態(tài)映射端口的機(jī)器要通信,就靠有映射的機(jī)器來(lái)?yè)?dān)當(dāng)“介紹”。

      就局域網(wǎng)和NAT的問(wèn)題實(shí)際上還很多,比如各自的局域網(wǎng)的結(jié)構(gòu)不同,局域網(wǎng)里可能又有子局域網(wǎng),局域網(wǎng)可能是NAT代理結(jié)構(gòu),但也可能是HTTP代理,Sock4、Sock5代理等結(jié)構(gòu),NAT又分嚴(yán)格的和非嚴(yán)格NAT,嚴(yán)格NAT限制很多,更不便于P2P。不過(guò),軟件不能實(shí)現(xiàn)的地方,可以考慮改變硬件結(jié)構(gòu),例如將嚴(yán)格NAT變?yōu)榉菄?yán)格NAT。如果硬件改變不得,那么Internet整體上就有10%的系統(tǒng)不能實(shí)現(xiàn)P2P,除非等到正處于研發(fā)的IPv6協(xié)議出來(lái)。

      P2P要解決的唯一技術(shù)難題是如何發(fā)現(xiàn)、定位和尋址對(duì)方,就是如何穿透NAT、HTTP、Sock等代理和如何穿透防火墻找到對(duì)方并建立起通信的問(wèn)題。由于絕大多數(shù)局域網(wǎng)是NAT代理結(jié)構(gòu),所以前面對(duì)NAT論述比較詳細(xì),也是網(wǎng)上討論最多的話題,相比之下,穿透Http、Sock代理就簡(jiǎn)單一些。此外,穿透NAT發(fā)現(xiàn)對(duì)等點(diǎn)的辦法還有一些,例如多播,但由于現(xiàn)有Internet對(duì)多播并不友好,同時(shí)多播是無(wú)連接和不可靠的,其實(shí)現(xiàn)有難度。

      許多軟件都是按照上述一些技術(shù)實(shí)現(xiàn)了P2P通信,著名的有MSN、QQ和BitTorrent下載軟件等。

      實(shí)際上,圍繞P2P通信,尤其是兩個(gè)不同局域網(wǎng)間的P2P,已經(jīng)有許多的P2P協(xié)議和開發(fā)包涌現(xiàn)。例如,Sun公司以Java寫的開發(fā)包Jxta,微軟在Windows XP平臺(tái)上有P2P的β版開發(fā)包,Intel公布.Net平臺(tái)上的P2P應(yīng)用開發(fā)工具包,放到微軟有關(guān).Net平臺(tái)的新聞?wù)军c(diǎn)www.上供用戶免費(fèi)下載。

      但是利用它們來(lái)開發(fā)程序,非常繁瑣,我們需要用簡(jiǎn)單的實(shí)現(xiàn)完成功能就可以了。

      如果想研究得更深入仔細(xì),請(qǐng)從Sun公司的網(wǎng)站和微軟網(wǎng)站下載開發(fā)包,或者在Google里

      搜索協(xié)議和開發(fā)包。

      下面其實(shí)有兩個(gè)實(shí)例,講述連通的過(guò)程,包括簡(jiǎn)單偽代碼。

      我們不希望在IP層實(shí)現(xiàn)我們的P2P,而是希望在應(yīng)用層,利用Windows提供的Socket建立P2P,至多下到用原始Raw Socket來(lái)寫P2P。

      首先看,我們對(duì)于公網(wǎng)有服務(wù)器做“中介(非中轉(zhuǎn))”的P2P怎么實(shí)現(xiàn)。

      原理講述:

      例如AB兩臺(tái)機(jī)器分別處于兩個(gè)不同的局域網(wǎng)后,由Server做中介,先看連接過(guò)程。

      A首先連接服務(wù)器,采用UDP發(fā)包給Server,這個(gè)包包括了A的用戶信息,類似于QQ的

      QQ號(hào)、呢稱等。Server方,可以用CSocket::GetPeerName()得到A的IP及端口,但得到的IP和端口應(yīng)該是A的代理網(wǎng)關(guān)的公網(wǎng)PublicIP及其映射端口NatPort,該映射端口就是A的代理網(wǎng)關(guān)為A的本次UDP通信臨時(shí)分配的Nat端口??梢詳嘌?,得到的端口一定不是A的內(nèi)網(wǎng)IP和內(nèi)網(wǎng)UDP端口。

      服務(wù)器然后將A的公網(wǎng)IP、映射端口、用戶信息等保存到(內(nèi)存列表或者數(shù)據(jù)庫(kù)),這樣標(biāo)志著A已經(jīng)上線。服務(wù)器馬上將其它在線的用戶信息發(fā)回給A,包括其它用戶的代理網(wǎng)關(guān)的公網(wǎng)IP及Nat端口。A同樣將在線用戶的這些信息保存并顯示為列表,期待A用戶做出選擇。

      對(duì)于B,同樣有上述的上線過(guò)程。

      當(dāng)A用戶做出選擇,要和在線的B用戶通信時(shí),A首先發(fā)UDP包給B的公網(wǎng)IP及Nat端口,并立即發(fā)一個(gè)UDP包給服務(wù)器,讓服務(wù)器去通知B,叫B給A也發(fā)一個(gè)UDP包。

      換句話說(shuō),1、A發(fā)包給PublicB, 2、A發(fā)包給Server,3、Server發(fā)包給PublicB,4、B發(fā)包給PublicA。

      上面的敘述用到了"Public"字樣,它代表代理網(wǎng)關(guān)的公網(wǎng)IP及其映射端口。

      由于A和B各自的網(wǎng)關(guān)都保存了各自的端口映射關(guān)系,發(fā)到網(wǎng)關(guān)的數(shù)據(jù),網(wǎng)關(guān)會(huì)按照這個(gè)映射關(guān)系轉(zhuǎn)發(fā)給A和B。

      當(dāng)A和B都分別收到對(duì)方發(fā)來(lái)的UDP包以后,連接宣告成功,服務(wù)器即可以脫離,AB即可以用UDP通信。

      何以如此麻煩?

      A在發(fā)UDP包給Server上線時(shí),A的網(wǎng)關(guān)(A.Gate)就分配一個(gè)Nat端口(A.NatPort)給A,用于A和Server間的本次UDP會(huì)話,但A的網(wǎng)關(guān)明確標(biāo)記,這個(gè)Nat端口,僅能用于A和Server之間的UDP通信,不能挪著它用。并且,這個(gè)臨時(shí)分配的端口,只能保持一個(gè)很短的時(shí)效,也許是一兩秒吧。這個(gè)時(shí)間內(nèi),如果A與Server沒(méi)有任何通信,那么這個(gè)映射端口就宣告無(wú)效。下次,A和Server又要通信時(shí),A的網(wǎng)關(guān)又會(huì)重新分配一個(gè)新的端口。這段表明三點(diǎn):

      1、A與Server的通信,需要A網(wǎng)關(guān)分配Nat端口來(lái)中轉(zhuǎn)。

      2、Nat端口只能用于A和Server間的通信。

      3、Nat端口存在生存期,長(zhǎng)時(shí)間A和Server無(wú)通信,該端口即宣告無(wú)效。

      就是這些麻煩,使得我們的連接過(guò)程必須繞很多彎。

      A和B的通信,就是借助事先AB分別與Server連接時(shí),在各自的網(wǎng)關(guān)處建立的端口映射來(lái)通信。為避免上面的2、3點(diǎn)麻煩,A和B在初次連接時(shí),必須幾乎同時(shí)向?qū)Ψ桨l(fā)包。

      如果A、B不同時(shí)發(fā)包給對(duì)方,它們各自的網(wǎng)關(guān)就會(huì)慮掉對(duì)方的包,因?yàn)樵摪皇荢erver發(fā)來(lái)的包,叫做不請(qǐng)自來(lái)的包。

      并且,即便AB各自的網(wǎng)關(guān)不慮掉非Server發(fā)來(lái)的包,它們各自的Nat端口也有一個(gè)時(shí)效。那么A與Server,B與Server就不得不發(fā)心跳包,以維持各自的映射端口,保證其不失效。

      上面的過(guò)程中,如果A和B建立連接失敗,可以循環(huán)這個(gè)過(guò)程,直到一個(gè)有限的次數(shù)之后,仍不能連接則宣告失敗。本文一部分的原文如下:

      Clients Behind Different NATs

      Suppose clients A and B both have private IP addresses and lie behind

      different network address translators.  The peer-to-peer application

      running on clients A and B and on server S each use UDP port 1234.  A

      and B have each initiated UDP communication sessions with server S,

      causing NAT A to assign its own public UDP port 62000 for A‘s session

      with S, and causing NAT B to assign its port 31000 to B‘s session

      with S, respectively.

      Server S

      18.181.0.31:1234

      |

      |

      +----------------------+----------------------+

      |                                             |

      NAT A                                         NAT B

      155.99.25.11:62000                            138.76.29.7:31000

      |                                             |

      |                                             |

      Client A                                      Client B

      10.0.0.1:1234                                 10.1.1.3:1234

      Now suppose that client A wants to establish a UDP communication

      session directly with client B.  If A simply starts sending UDP

      requests to B‘s public address, 138.76.29.7:31000, then NAT B will

      typically discard these incoming messages because the source address

      and port number does not match those of S, with which the original

      outgoing session was established.  Similarly, if B simply starts

      sending UDP requests to A‘s public address, then NAT A will discard

      these messages.

      Suppose A starts sending UDP requests to B‘s public address, however,

      and simultaneously relays a request through server S to B, asking B

      to start sending UDP requests to A‘s public address.  A‘s outgoing

      messages directed to B‘s public address (138.76.29.7:31000) will

      cause NAT A to open up a new communication session between A‘s

      private address and B‘s public address.  At the same time, B‘s

      messages to A‘s public address (155.99.25.11:62000) will cause NAT B

      to open up a new communication session between B‘s private address

      and A‘s public address.  Once the new UDP sessions have been opened

      up in each direction, client A and B can communicate with each other

      directly without further reference to or burden on the "introduction"

      server S

      大致就如此。以下是上述過(guò)程的一些偽代碼,不太容易懂,不如看前面的論述。

      下面將討論,A和B同時(shí)發(fā)包的另外一個(gè)辦法,以及關(guān)于靜態(tài)端口映射、誰(shuí)能做"中介"、

      是否可以建立TCP通信等細(xì)節(jié)及其引申。

      const TCHAR*  ServerIP   = _T("61.10.10.10");  //中介服務(wù)器,事先配置的

      const UINT    ServerPort = 4500;               //中介服務(wù)器UDP端口,事先配置的

      TCHAR   PubIP[256]; //對(duì)方機(jī)器的代理網(wǎng)關(guān)的公網(wǎng)IP

      UINT    PubPort;    //對(duì)方機(jī)器的代理網(wǎng)關(guān)的公網(wǎng)映射端口

      UINT    ClientPort = 4501;               //A和B的UDP端口

      連接服務(wù)器用UDP,下面是客戶方(AB的Socket)

      class CClientSocket : public CSocket

      {

      public:

      virtual void OnReceive( int nErrCode );

      }

      void CClientSocket::OnReceive( int nErrCode )

      {

      int       nFlag, *pFlag;  //UDP包標(biāo)志,位于包頭4個(gè)字節(jié)

      TCHAR     PeerIP[128];    //UDP對(duì)方的IP

      UINT      PeerPort;       //UDP對(duì)方的端口

      char      RecBuf[64];     //假定包尺寸為64

      //此處分析出對(duì)方IP和端口,即PeerIP和PeerPort

      SOCKADDR  sa;

      int       SockAddrLen = sizeof(sa);

      GetPeerName( &sa, &SockAddrLen );

      //從sa中取出PeerIP和PeerPort

      Receive( RecBuf, 64 );

      pFlag = (int*)RecBuf;

      nFlag = *pFlag;

      if( lstrcmp( PeerIP, ServerIP ) == 0 )  //如果是服務(wù)器返回的信息

      {

      switch( nFlag )

      {

      case  0:   //標(biāo)識(shí)和服務(wù)器連接成功,RecBuf是服務(wù)器返回的其它在線用戶

      //的信息(包括對(duì)方的公網(wǎng)IP及端口),這里假定是B的信息

      //從RecBuf取出B的代理網(wǎng)關(guān)的IP和端口放入PeerIP和PeerPort

      lstrcpy( PubIP, PeerIP ); //PeerIP應(yīng)該是對(duì)方的代理網(wǎng)關(guān)的公網(wǎng)IP

      PubPort = PeerPort;       //同時(shí)PeerPort應(yīng)該是對(duì)方的代理網(wǎng)關(guān)的公網(wǎng)映射端口

      //接下來(lái),給B的代理公網(wǎng)IP發(fā)一個(gè)UDP包,填充RecBuf,并使標(biāo)志為0

      SendTo( RecBuf, 64, PubPort, PubIP );

      //馬上叫服務(wù)器通知B,要B給A發(fā)一個(gè)UDP包,填充RecBuf,并使標(biāo)志為1

      SendTo( RecBuf, 64, ServerPort, ServerIP );

      break;

      case  1: //標(biāo)識(shí)是來(lái)自服務(wù)器的通知,叫我(B)發(fā)一個(gè)UDP給A

      //RecBuf里有A的代理公網(wǎng)IP和端口,取出來(lái),放入PeerIP和PeerPort

      lstrcpy( PubIP, PeerIP ); //PeerIP應(yīng)該是對(duì)方的代理網(wǎng)關(guān)的公網(wǎng)IP

      PubPort = PeerPort;       //同時(shí)PeerPort應(yīng)該是對(duì)方的代理網(wǎng)關(guān)的公網(wǎng)映射端口

      //給A發(fā)一個(gè)UDP包,填充RecBuf,并使標(biāo)志為1

      SendTo( RecBuf, 64, PubPort, PubIP );

      break;

      .

      .

      .

      default:

      break;

      }

      }

      else //其它對(duì)等客戶返回的信息

      {

      switch( nFlag )

      {

      case  0: //標(biāo)識(shí)直接收到A發(fā)的UDP包

      break;

      case  1:  //標(biāo)識(shí)是B發(fā)回的UDP包,但,是靠服務(wù)器通知B發(fā)的

      //至此,可以判斷AB互相是否連接成功,就是判斷A發(fā)給B的UDP包B收到,而B發(fā)

      //給A的UDP包A也收到,那么連接就是成功的。否則重復(fù)上面的過(guò)程。

      break;

      .

      .

      .

      default:

      break;

      }

      }

      }

      客戶方先連接服務(wù)器,服務(wù)器收到后,返回所有在線的對(duì)等點(diǎn)用戶信息

      CClientSocket  cs;

      char sBuf[64];  //sBuf的包標(biāo)識(shí)為0,你可以填充其它任何信息,比如用戶信息

      cs.Create( ClientPort, SOCK_DGRAM );

      cs.SendTo( sBuf, 64, ServerPort, ServerIP );

      class CServerSocket : public CSocket

      {

      public:

      virtual void OnReceive( int nErrCode );

      }

      void CServerSocket::OnReceive( int nErrCode )

      {

      int       nFlag, *pFlag;  //UDP包標(biāo)志,位于包頭4個(gè)字節(jié)

      TCHAR     PeerIP[128];    //UDP對(duì)方的IP

      UINT      PeerPort;       //UDP對(duì)方的端口

      char      RecBuf[64];     //假定包尺寸為64

      //此處分析出對(duì)方IP和端口,即PeerIP和PeerPort

      SOCKADDR  sa;

      int       SockAddrLen = sizeof(sa);

      GetPeerName( &sa, &SockAddrLen );

      //從sa中取出PeerIP和PeerPort

      Receive( RecBuf, 64 );

      pFlag = (int*)RecBuf;

      nFlag = *pFlag;

      switch( nFlag )

      {

      case  0:  //標(biāo)識(shí)有客戶連接

      //給該客戶返回所有在線用戶

      break;

      case  1:  //來(lái)自A的通知,要我通知B,叫B發(fā)一個(gè)UDP包給A的公網(wǎng)IP

      //從RecBuf中取出B的IP和端口放入PeerIP和PeerPort,填充RecBuf,標(biāo)志為1

      SendTo( RecBuf, 64, PeerPort, PeerIP );

      break;

      }

      }

      【責(zé)任編輯:P2Psky】

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多