Linux socket跨局域网聊天和文件传输
一直想寫一個跨局域網聊天和文件傳輸,以及視頻聊天的軟件,這兩天剛好閑著沒啥事就把代碼寫完了,代碼已經上傳至github:https://github.com/vinllen/chat
其實之前想法P2P模式,P2P的話必須穿透NAT,現在的NAT有4種模式:
- 1.Full cone NAT,亦即著名的一對一(one-to-one)NAT
一旦一個內部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有發自iAddr:port1的包都經由eAddr:port2向外發送。任意外部主機都能通過給eAddr:port2發包到達iAddr:port1
- 2.Address-Restricted cone NAT
一旦一個內部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有發自iAddr:port1的包都經由eAddr:port2向外發送。任意外部主機(hostAddr:any)都能通過給eAddr:port2發包到達iAddr:port1的前提是:iAddr:port1之前發送過包到hostAddr:any. "any"也就是說端口不受限制
- 3.Port-Restricted cone NAT
一旦一個內部地址(iAddr:port1)映射到外部地址(eAddr:port2),所有發自iAddr:port1的包都經由eAddr:port2向外發送。一個外部主機(hostAddr:port3)能夠發包到達iAddr:port1的前提是:iAddr:port1之前發送過包到hostAddr:port3.
- 4.Symmetric NAT(對稱NAT)
只有曾經收到過內部主機封包的外部主機,才能夠把封包發回
對于第1種特別簡單,因為端口存在映射,只要把包發網出口路由的端口即可,路由會幫你轉發
對于第2,3種情況,可以采用如下辦法(內容來自該博客:點擊打開鏈接):
假設網絡模型如下:
限制性錐NAT 和端口限制性錐NAT (簡稱限制性NAT ),穿透限制性錐NAT 會丟棄它未知的源地址發向內部主機的數據包。所以如果現在ClientA-1 直接發送UDP 數據包到ClientB-1 ,那么數據包將會被NAT-B 無情的丟棄。所以采用下面的方法來建立ClientA-1 和ClientB-1 之間的通信。
- 1 .ClientA-1 (202.103.142.29:5000 )發送數據包給Server ,請求和ClientB-1 (221.10.145.84:6000 )通信。
- 2. Server 將ClientA-1 的地址和端口(202.103.142.29:5000 )發送給ClientB-1 ,告訴ClientB-1 ,ClientA-1 想和它通信。
- 3. ClientB-1 向ClientA-1 (202.103.142.29:5000 )發送UDP 數據包,當然這個包在到達NAT-A 的時候,還是會被丟棄,這并不是關鍵的,因為發送這個UDP 包只是為了讓NAT-B 記住這次通信的目的地址:端口號,當下次以這個地址和端口為源的數據到達的時候就不會被NAT-B 丟棄,這樣就在NAT-B 上打了一個從ClientB-1 到ClientA-1 的孔。
- 4. 為了讓ClientA-1 知道什么時候才可以向ClientB-1 發送數據,所以ClientB-1 在向ClientA-1 (202.103.142.29:5000 )打孔之后還要向Server 發送一個消息,告訴Server 它已經準備好了。
- 5. Server 發送一個消息給ClientA-1 ,內容為:ClientB-1 已經準備好了,你可以向ClientB-1 發送消息了。
- 6. ClientA-1 向ClientB-1 發送UDP 數據包。這個數據包不會被NAT-B 丟棄,以后ClientB-1 向ClientA-1 發送的數據包也不會被ClientA-1 丟棄,因為NAT-A 已經知道是ClientA-1 首先發起的通信。至此,ClientA-1 和ClientB-1 就可以進行通信了。
1.同時開放TCP ( Simultaneous TCP open )策略
如果一個 對稱 NAT 接收到一個來自 本地 私有網 絡 外面的 TCP SYN 包, 這 個包想 發 起一個 “ 引入” 的 TCP 連 接,一般來 說 , NAT 會拒 絕這 個 連 接 請 求并扔掉 這 個 SYN 包,或者回送一個TCP RST (connection reset ,重建 連 接)包 給請 求方。但是,有一 種 情況 卻會接受這個“引入”連接。
RFC 規定:對于對稱NAT , 當 這 個接收到的 SYN 包中的源IP 地址 : 端口、目 標 IP 地址 : 端口都與NAT 登 記 的一個已 經 激活的 TCP 會 話 中的地址信息相符 時 , NAT 將會放行 這 個 SYN 包。 需要 特 別 指出 的是:怎樣才是一個已經激活的TCP 連接?除了真正已經建立完成的TCP 連接外,RFC 規范指出: 如果 NAT 恰好看到一個 剛剛發 送出去的一個 SYN 包和 隨之 接收到的SYN 包中的地址 :端口 信息相符合的 話 ,那 么 NAT 將會 認為這 個 TCP 連 接已 經 被激活,并將允 許這 個方向的 SYN 包 進 入 NAT 內部。 同時開放TCP 策略就是利用這個時機來建立連接的。
如果 Client A -1 和 Client B -1 能 夠 彼此正確的 預 知 對 方的 NAT 將會 給 下一個 TCP 連 接分配的公網 TCP 端口,并且兩個客 戶 端能 夠 同 時 地 發 起一 個面向對方的 “ 外出 ” 的 TCP 連 接 請求 ,并在 對 方的 SYN 包到達之前,自己 剛發 送出去的 SYN 包都能 順 利的穿 過 自己的 NAT 的 話 ,一條端 對 端的 TCP 連 接就 能 成功地建立了 。
2.UDP 端口猜測策略
同時開放TCP 策略非常依賴于猜測對方的下一個端口,而且強烈依賴于發送連接請求的時機,而且還有網絡的不確定性,所以能夠建立的機會很小,即使Server 充當同步時鐘的角色。下面是一種通過UDP 穿透的方法,由于UDP 不需要建立連接,所以也就不需要考慮“同時開放”的問題。
為了介紹ClientB-1 的詭計,先介紹一下STUN 協議。STUN (Simple Traversal of UDP Through NATs )協議是一個輕量級協議,用來探測被NAT 映射后的地址:端口。STUN 采用C/S 結構,需要探測自己被NAT 轉換后的地址:端口的Client 向Server 發送請求,Server 返回Client 轉換后的地址:端口。
參考4.2 節中穿透NAT 的步驟2 ,當ClientB-1 收到Server 發送給它的消息后,ClientB-1 即打開3 個socket 。socket-0 向STUN Server 發送請求,收到回復后,假設得知它被轉換后的地址:端口( 221.10.145.84:600 5 ),socket-1 向ClientA-1 發送一個UDP 包,socket-2 再次向另一個STUN Server 發送請求,假設得到它被轉換后的地址:端口( 221.10.145.84:60 20 )。通常,對稱NAT 分配端口有兩種策略,一種是按順序增加,一種是隨機分配。如果這里對稱NAT 使用順序增加策略,那么,ClientB-1 將兩次收到的地址:端口發送給Server 后,Server 就可以通知ClientA-1 在這個端口范圍內猜測剛才ClientB-1 發送給它的socket-1 中被NAT 映射后的地址:端口,ClientA-1 很有可能在孔有效期內成功猜測到端口號,從而和ClientB-1 成功通信。
/************************************華麗分割線**********************************************************/ 以上內容大部分參考維基百科和chengweiv5的博客,我自己也寫了代碼,嘗試用第二種方式去穿透我們學校所在的NAT,結果悲劇了,找了好幾天的問題也沒找出來到底是代碼的原因呢還是NAT限制為第4種的原因呢。 But項目不能這么擱淺了。我采用了另外一條曲線救國的路線,就跟現在QQ模式一樣,用中轉服務器進行消息轉發實現。 1.首先搞了一臺具有公網ip的服務器 2.配置好環境后(比如iptables等),把服務器代碼放置服務器,運行 3.客戶端連接后就可以發送文件和聊天了 That's all,就這么簡單。 唯一需要說明的就是發送文件時我調用的是sendfile的系統調用,接收文件調用了Pat Patterson的包裹函數:利用splice接收文件,理論上這兩個函數是直接在內核態進行文件傳遞,而不用在內核態和普通態進行數據的拷貝,減少時間。我測試了一下,對幾M大小的文件都沒問題,不過貌似文件大了貌似傳不動了,目測sendfile有大小限制。。。這個就之后再改改了。 最后一點,本來還要實現視頻傳輸的,我的想法就是用opencv調用本地攝像頭,然后把圖片按每秒固定幀數截下來,按文件方法傳輸,再在對端對圖片進行拼接成視頻。后來感覺有點麻煩,最后上網一查,果然我做的部分就是重造輪子的活,現在直接都有現成的文件傳輸協議。這部分也等以后有時間再去完善吧。 Finally,?如果大家有誰有想法,可以和我交流交流,一起學習進步
總結
以上是生活随笔為你收集整理的Linux socket跨局域网聊天和文件传输的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 已经出狱的李一男和即将出狱的王欣,还能赶
- 下一篇: Winsock 10106错误解决方法