用TCP穿透NAT(TCP打洞)的實現

2021-09-07 09:55:46 字數 3716 閱讀 4005

目錄

tcp穿透原理

程式思路

宣告上**

執行示例

我們假設在兩個不同的區域網後面分別有2臺客戶機a和 b,ab所在的區域網都分別通過乙個路由器接入網際網路。網際網路上有一台伺服器s。 

現在ab是無法直接和對方傳送資訊的,ab都不知道對方在網際網路上真正的ip和埠, ab所在的區域網的路由器只允許內部向外主動傳送的資訊通過。對於b直接傳送給a的路由器的訊息,路由會認為其「不被信任」而直接丟棄。 

要實現 ab直接的通訊,就必須進行以下3步:a首先連線網際網路上的伺服器s並傳送一條訊息(對於udp這種無連線的協議其實直接初始會話傳送訊息即可),這樣s就獲取了a在網際網路上的實際終端(傳送訊息的ip和埠號)。接著 b也進行同樣的步驟,s就知道了ab在網際網路上的終端(這就是「打洞」)。接著s分別告訴a和b對方客戶端在網際網路上的實際終端,也即s告訴a客戶b的會話終端,s告訴b客戶a的會話終端。這樣,在ab都知道了對方的實際終端之後,就可以直接通過實際終端傳送訊息了(因為先前雙方都向外傳送過訊息,路由上已經有允許資料進出的訊息通道)。

1:啟動伺服器,監聽埠8877

2:第一次啟動客戶端(稱為client1),連上伺服器,伺服器將返回字串first,標識這個是client1,同時,伺服器將記錄下這個客戶端的(經過轉換之後的)ip和埠。

3:第二次啟動客戶端(稱為client2),連上伺服器,伺服器將向其返回自身的傳送埠(稱為port2),以及client1的(經過轉換之後的)ip和埠。

4:然後伺服器再發client1返回client2(經過轉換之後的)ip和埠,然後斷開與這兩個客戶端的連線(此時,伺服器的工作已經全部完成了)

5:client2嘗試連線client1,這次肯定會失敗,但它會在路由器上留下記錄,以幫忙client1成功穿透,連線上自己,然後設定port2埠為可重用埠,並監聽埠port2。

6:client1嘗試去連線client2,前幾次可能會失敗,因為穿透還沒成功,如果連線10次都失敗,就證明穿透失敗了(可能是硬體不支援),如果成功,則每秒向client2傳送一次hello, world

7:如果client1不斷出現send message: hello, world,client2不斷出現recv message: hello, world,則證明實驗成功了,否則就是失敗了。

伺服器端:

/*

檔案:server.c

ps:第乙個連線上伺服器的客戶端,稱為client1,第二個連線上伺服器的客戶端稱為client2

這個伺服器的功能是:

1:對於client1,它返回"first",並在client2連線上之後,將client2經過轉換後的ip和port發給client1;

2:對於client2,它返回client1經過轉換後的ip和port和自身的port,並在隨後斷開與他們的連線。

*/#include

#include

#include

#include

#include

#include

#include

#include

#include

#define maxline 128

#define serv_port 8877

//發生了致命錯誤,退出程式

void error_quit(const

char *str)

int main(void

)

//對於第二個鏈結,將其的ip+port傳送給第乙個鏈結,

//將第乙個鏈結的資訊和他自身的port返回給它自己,

//然後斷開兩個鏈結,並重置計數器

else

if( count == 2

)

//如果程式執行到這裡,那肯定是出錯了

else

error_quit(

"bad required");

}return0;

}

客戶端:

/*

檔案:client.c

ps:第乙個連線上伺服器的客戶端,稱為client1,第二個連線上伺服器的客戶端稱為client2

這個程式的功能是:先連線上伺服器,根據伺服器的返回決定它是client1還是client2,

若是client1,它就從伺服器上得到client2的ip和port,連線上client2,

若是client2,它就從伺服器上得到client1的ip和port和自身經轉換後的port,

在嘗試連線了一下client1後(這個操作會失敗),然後根據伺服器返回的port進行監聽。

這樣以後,就能在兩個客戶端之間進行點對點通訊了。

*/#include

#include

#include

#include

#include

#include

#include

#include

#include

#define maxline 128

#define serv_port 8877typedef

struct

server;

//發生了致命錯誤,退出程式

void error_quit(const

char *str)

int main(int argc, char **ar**)

else

break

; }

strcpy(buffer,

"hello, world\n");

//連線成功後,每隔一秒鐘向對方(客戶端2)傳送一句hello, world

while( 1

)

}//第二個客戶端的行為

else

close(connfd);}}

return0;

}

(第乙個終端)

qch@qch ~/program/tcode $ gcc server.c -o server

qch@qch ~/program/tcode $ ./server &

[1] 4688

qch@qch ~/program/tcode $ gcc client.c -o client

qch@qch ~/program/tcode $ ./client localhost

get: first

ff: 127.0.0.1 38052

send message: hello, world

send message: hello, world

send message: hello, world

.................

第二個終端:

qch@qch ~/program/tcode $ ./client localhost

get: 127.0.0.1 38073 38074

connect error

recv message: hello, world

recv message: hello, world

recv message: hello, world

..................

出處:個人注:

我認為,service的作用遠不止這些,service可以做一些驗證連通性、資料校驗等等的事情,只有當a和b真正開始通訊了,這時才考慮斷開a、b與service的鏈結。

TCP打洞的小問題

過程和網上方法的差不多了,tcp打洞。s 伺服器 a和b分別是在路由後面的機器,a想和b連線,a和b分別和伺服器建立乙個主連線用於通訊.a和伺服器的協助打洞套接字建立連線,讓伺服器知道nat a轉換後的公網ip位址和埠等資訊。b也和伺服器建立連線,讓伺服器知道nat b轉換後的公網ip位址和埠等資訊...

使用TCP協議的穿透技術

其實很早我就已經實現了使用tcp協議穿透nat了,但是苦於一直沒有時間,所以沒有寫出來,現在終於放假有一點空閒,於是寫出來共享之。一直以來,說起nat穿透,很多人都會被告知使用udp打孔這個技術,基本上沒有人會告訴你如何使用tcp協議去穿透 甚至有的人會直接告訴你tcp協議是無法實現穿透的 但是,眾...

使用TCP協議的NAT穿透技術

要了解如何使用tcp穿透nat,就要首先看看如何使用udp穿透nat。假設,我們在兩個不同的區域網後面分別有2臺客戶機a和 b,ab所在的區域網都分別通過乙個路由器接入網際網路。網際網路上有一台伺服器s。現在a b是無法直接和對方傳送資訊的,a b都不知道對方在網際網路上真正的ip和埠,ab所在的區...