前言:
最近我用java做了一個C/S的類似QQ之類的IM系統(即時通訊系統),遇到了不能跨局域網通訊的問題,經過在網上,和書上查閱了一些資料,了解了一些情況,現在就總結一下我的解決方案吧(本人也是在不斷錯誤中學習,如果有什么不對的地方,請大家多多指教)。
問題描述:
一般情況下,只能在同一個子網即同一個虛擬局網里通訊,或者子網訪問外網,外網訪問不了內網。因為虛擬局域網相對於外網都是透明的,所以外網是不能直接訪問子網,舉個例子:校園網里的學生信息管理系統(MIS),需要是校園網里面的IP地址才能訪問,校園網以外的IP是不能訪問,這樣的做法的好處不用我多說吧。。
而即時通訊需要相互交流信息,所以需要相互都能訪問到,問題是:如何跨子網通訊?
問題分析:
2.ClientA在子網,ClientB在外網
者IP的數據包;如果ClientA發送數據包給ClientB,ClientB接受數據包的IP來源並不是ClientA,而已中轉站(路由器)的IP。
解決方案:
單,這里就不多說了。
吧。
1)NAT
這里默認是用NAT,端口號沒有轉換,如果是NAPT,實現的原理也是差不多的,只是細節不同。
關於第二種情況,原理如下:
NATA:路由器對外的wlanIP:168.38.2.2;路由器對內的lanIP:192.168.1.10
1.首先,A(內網IP)先向B(外網IP)發送UDP包,NAT會產生session,存放192.168.1.10-- >168.38.2.225的映射關系
2.接下來,只要B把信息發給NATA,NATA會自動把信息轉發給A
關於第三種情況,原理如下:
務器,記錄了所有客戶端的真實IP(如果是內網IP就記錄內網IP),我是用TCP來實現客戶端和服務器的通訊,這里要用到了TCP穿透,這里先不講,最后總結說一下。
![]()
或者如圖:(ps:圖片是網上下載的)
務器--客戶端之間可以相互通訊。客戶端會向客戶端發送自身的真實IP(如A:192.168.1.110),服務器接受到這信息之后,同時也會知道信息源的IP(如:NATA的外網IP:210.38.196.110),因為接受方總能知道信息包的最直接來源。此時,服務器就記錄了ClientA的IP、NATA外網IP和ClientB的IP、NATB外網IP。
要想A<------>B之間無需經過第三方的通訊,必須在NATA中為B打個洞,在NATB中為A打個洞。
NATB發送到NATA的,都會轉發到A子網中,此過程叫NATA為B打洞。同理NATB也可以為A打洞。
具體過程:server會發送信息告知A,B的NATB的外網IP;告知B,A的NATA的外網IP。這樣子,A可以先發送一個數據包到NATB(外網IP:210.38.196.30),NATA會生成一個session記錄A————>NATB的映射關系。數據包到達NATB時,NATB因為還未為A打洞,會丟包。然后B向NATA(外網IP:210.38.196.110)發送數據包,NATB會生成一個session記錄B————>NATA的映射關系。此時,NATA接受到來自NATB的數據包,會查找下session映射,發現有A————>NATB的映射關系,會把包轉發給A。只要A再發信息給NATB時,NATB也會根據session來轉發給B。雙方打洞完成。
利用第三方服務器來幫P2P對等點之間的UDP打洞,是比較全面的方案,此方案適用於P2P對等點在任何網絡點(說得可能比較絕對吧,大家有什么不同意見記得提出來哦,純屬個人的偏見)
總結:
立方打洞)
樣)
一樣)
由於我開發的只是簡單的即時通訊系統,可能很多復雜的情況我沒有考慮進去,例如存在多個NAT的嵌套,NAPTIP地址端口號轉換沒有考慮進去,路由器中的session的生命周期的不確定(有時候是幾分鍾,有時候幾個小時不定),所以需要定期地進行穿透等等等等。