小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

C#代碼實(shí)現(xiàn)TCP穿透(打洞)

 _明心見性_ 2021-12-07

?內(nèi)網(wǎng)之間實(shí)現(xiàn)TCP通訊需要用到內(nèi)網(wǎng)穿透技術(shù),具體原理網(wǎng)上都有,參考:

https://blog.csdn.net/leisure512/article/details/4900191

https://blog.csdn.net/aaron133/article/details/79206257

TCP穿透成功的條件需要兩邊網(wǎng)絡(luò)都是錐形NAT(或者至少一端網(wǎng)絡(luò)是錐形NAT),具體可以參考

https://blog.csdn.net/h_armony/article/details/45167975

里面有給出各種NAT說明:

有公網(wǎng)IP的寬帶:比如聯(lián)通的ADSL,這類寬帶會(huì)給每個(gè)用戶分配一個(gè)公網(wǎng)IP,所以其NAT類型取決于用戶所選用的路由器,大部分家用路由器都是端口限制錐型NAT;

無公網(wǎng)IP的寬帶:比如寬帶通,這類寬帶給用戶分配的是局域網(wǎng)IP,連接公網(wǎng)的NAT是運(yùn)營商的,一般都是對稱型NAT;

移動(dòng)互聯(lián)網(wǎng):跟“無公網(wǎng)IP的寬帶”類似,分配給手機(jī)的是局域網(wǎng)IP,出口基本都是對稱型NAT;

大公司路由器:大部分都把路由器配置成對稱型NAT。

這邊使用VS2010 C#實(shí)現(xiàn):

服務(wù)端代碼:

static void Main(string[] args)
{
int port = 555;
IPEndPoint ipe = new IPEndPoint(IPAddress.Any, port);
Socket sSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sSocket.Bind(ipe);
sSocket.Listen(100);
Console.WriteLine(“監(jiān)聽已經(jīng)打開,請等待”);

        while (true)
        {
            Socket serverSocket1 = sSocket.Accept();
            Console.WriteLine('連接已經(jīng)建立');
            string recStr = '';
            byte[] recByte = new byte[4096];
            int bytes = serverSocket1.Receive(recByte);
            IPEndPoint ep1 = (IPEndPoint)serverSocket1.RemoteEndPoint;
            Console.WriteLine(' from {0}', ep1.ToString()); 
            recStr = Encoding.ASCII.GetString(recByte, 0, bytes);
            Console.WriteLine('客戶端1:{0}', recStr);

            Socket serverSocket2 = sSocket.Accept();
            bytes = serverSocket2.Receive(recByte);
            IPEndPoint ep2 = (IPEndPoint)serverSocket2.RemoteEndPoint;
            Console.WriteLine(' from {0}', ep2.ToString());
            recStr = Encoding.ASCII.GetString(recByte, 0, bytes);
            Console.WriteLine('客戶端2:{0}', recStr);


            byte[] sendByte =Encoding.ASCII.GetBytes(ep1.ToString() + ':' + ep2.ToString());  
            serverSocket1.Send(sendByte, sendByte.Length, 0);

            sendByte = Encoding.ASCII.GetBytes(ep2.ToString() + ':' + ep1.ToString());  
            serverSocket2.Send(sendByte, sendByte.Length, 0);

            serverSocket1.Close();
            serverSocket2.Close();
        } 
          
    } 

功能:兩邊客戶端連接服務(wù)器后將映射的外網(wǎng)IP和端口號傳給雙方。

客戶端代碼

static void Main(string[] args)
{
string host = “115.21.X.X”;//服務(wù)端IP地址
int port = 555;
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//設(shè)置端口可復(fù)用
clientSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
//連接服務(wù)端
clientSocket.Connect(host, port);
Console.WriteLine(“Connect:” + host + ' ' + port);

        string data = 'hello,Server!';
        clientSocket.Send(Encoding.ASCII.GetBytes(data));
        Console.WriteLine('Send:' + data);
        byte[] recBytes = new byte[100];
        //獲取到雙方的ip及端口號
        int bytes = clientSocket.Receive(recBytes, recBytes.Length, 0);
       string result = Encoding.ASCII.GetString(recBytes, 0, bytes);
       Console.WriteLine('Recv:' +result);
       clientSocket.Close();

       string[] ips = result.Split(':'); 
       int myPort = Convert.ToInt32(ips[1]);
       string otherIp = ips[2];
       int otherPort = Convert.ToInt32(ips[3]);


       Socket mySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
       mySocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        //綁定到之前連通過的端口號
       IPEndPoint ipe = new IPEndPoint(IPAddress.Any, Convert.ToInt32(myPort));
       mySocket.Bind(ipe);
        //嘗試5次連接
       for (int j = 0; j < 5; j++)
       {
           try
           {
               mySocket.Connect(otherIp, otherPort);
               Console.WriteLine('Connect:成功{0},{1}', otherIp,otherPort);
               break;
           }
           catch (Exception)
           {
               Console.WriteLine('Connect:失敗');
                // otherPort++;//如果是對稱NAT,則有可能客戶端的端口號已經(jīng)改變,正常有規(guī)律的應(yīng)該是順序加1,可以嘗試+1再試(我使用手機(jī)熱點(diǎn)連接的時(shí)候端口號就變成+1的了)除非是碰到隨機(jī)端口,那就不行了。
           }

       }
       while (true)
       {
           mySocket.Send(Encoding.ASCII.GetBytes('hello,the other client!'));

           byte[] recv = new byte[4096];
           int len = mySocket.Receive(recv, recv.Length, 0);
           result = Encoding.ASCII.GetString(recv, 0, len);
           Console.WriteLine('recv :' + result);

           Thread.Sleep(1000); 
       }

}

另一邊客戶端也一樣。連接服務(wù)器后,可以綁定之前的端口號復(fù)用,但如果碰到一端是對稱NAT時(shí)每次使用端口號會(huì)不一樣時(shí),這樣就得通過預(yù)測下次可能使用的端口號來連通。如:使用手機(jī)熱點(diǎn)網(wǎng)絡(luò)連接服務(wù)器時(shí),獲取到它使用的端口號是56324,等到下一次客戶端互相連接使用56325才連上。
?

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

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多