激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - C# - C#開發之Socket網絡編程TCP/IP層次模型、端口及報文等探討

C#開發之Socket網絡編程TCP/IP層次模型、端口及報文等探討

2020-12-19 15:36C#菜鳥教程 C#

我們在講解Socket編程前,先看幾個和Socket編程緊密相關的概念

1、tcp/ip層次模型

當然這里我們只討論重要的四層

01,應用層(application):應用層是個很廣泛的概念,有一些基本相同的系統級tcp/ip應用以及應用協議,也有許多的企業應用和互聯網應用。http協議在應用層運行。

02,傳輸層(tanspot):傳輸層包括udp和tcp,udp幾乎不對報文進行檢查,而tcp提供傳輸保證。

03,網絡層(netwok):網絡層協議由一系列協議組成,包括icmp、igmp、rip、ospf、ip(v4,v6)等。

04,鏈路層(link):又稱為物理數據網絡接口層,負責報文傳輸。

然后我們來看下tcp層次模型圖

C#開發之Socket網絡編程TCP/IP層次模型、端口及報文等探討

從上圖中可以看出,應用程序在應用層運行,在傳輸層,在數據前加上了tcp頭,在

網絡層加上的ip頭,在數據鏈路層加上了幀。

2、端口

端口號范圍:0-65535,總共能表示65536個數。

按端口號可分為3大類

  (1)公認端口(wellknownports):從0到1023,它們緊密綁定(binding)于一些服務。通常這些端口的通訊明確表明了某種服務的協議。例如:80端口實際上總是http通訊。

  (2)注冊端口(registeredports):從1024到49151。它們松散地綁定于一些服務。也就是說有許多服務綁定于這些端口,這些端口同樣用于許多其它目的。例如:許多系統處理動態端口從1024左右開始。

  (3)動態和/或私有端口(dynamicand/orprivateports):從49152到65535。理論上,不應為服務分配這些端口。實際上,機器通常從1024起分配動態端口。

3.tcp和udp報文

下面一起來看下tcp和udp的報文圖

C#開發之Socket網絡編程TCP/IP層次模型、端口及報文等探討

從圖中我們可以看出tcp和udp中都有校驗和,但是在udp報文中,一般不使用校驗和,這樣可以加快數據傳輸的速度,但是數據的準確性可能會受到影響。換句話說,tcp協議都有校驗和,為了保證傳輸數據的準確性。

3.socket

socket包括ip地址和端口號兩部分,程序通過socket來通信,socket相當于操作系統的一個組件。socket作為進程之間通信機制,通常也稱作”套接字”,用于描述ip地址和端口號,是一個通信鏈的句柄。說白了,就是兩個程序通信用的。

生活案例對比:

socket之間的通信可以類比生活中打電話的案例。任何用戶在通話之前,首先要占有一部電話機,相當于申請一個socket,同時要知道對方的號碼,相當于對方有一個固定的socket,然后向對方撥號呼叫,相當于發出連接請求。假如對方在場并空閑,拿起 電話話筒,雙方就可以進行通話了。雙方的通話過程,是一方向電話機發出信號和對方從電話機接收信號的過程,相當于向socket發送數據和從socket接收數據。通話結束后,一方掛起電話機,相當于關閉socket,撤銷連接。

注意:socket不僅可以在兩臺電腦之間通信,還可以在同一臺電腦上的兩個程序間通信。

4,端口進階(深入)

通過ip地址確定了網絡中的一臺電腦后,該電腦上可能提供很多提供服務的應用,每一個應用都對應一個端口。

在internet上有很多這樣的主機,這些主機一般運行了多個服務軟件 ,同時提供幾種服務,每種服務都打開一個socket,并綁定到一個端口上,不同的端口對應于不同的服務(應用程序)

例如:http 使用80端口, ftp使用21端口 smtp使用25端口

5.socket分類

socket主要有兩種類型:

流式socket

是一種面向連接的socket,針對于面向連接的tcp服務應用,安全,但是效率低

2,數據報式socket

是一種無連接的socket,對應于無連接的udp服務應用,不安全,但效率高

6. socket一般應用模式(服務器端和客戶端)

服務器端的socket(至少需要兩個)

01.一個負責接收客戶端連接請求(但不負責與客戶端通信)

02.每成功接收到客戶端的連接便在服務器端產生一個對應的復雜通信的socket

021.在接收到客戶端連接時創建

022. 為每個連接成功的客戶端請求在服務器端都創建一個對應的socket(負責和客戶端通信)

客戶端的socket

必須指定要連接的服務器地址和端口

通過創建一個socket對象來初始化一個到服務器端的tcp連接

C#開發之Socket網絡編程TCP/IP層次模型、端口及報文等探討

通過上圖,我們可以看出,首先服務器會創建一個負責監聽的socket,然后客戶端通過socket連接到服務器指定端口,最后服務器端負責監聽的socket,監聽到客戶端有連接過來了,就創建一個負責和客戶端通信的socket。

下面我們來看下socket更具體的通信過程:

socket的通訊過程

服務器端:

01,申請一個socket

02,綁定到一個ip地址和一個端口上

03,開啟偵聽,等待接收連接

客戶端:

01,申請一個socket

02,連接服務器(指明ip地址和端口號)

服務器端接收到連接請求后,產生一個新的socket(端口大于1024)與客戶端建立連接并進行通信,原監聽socket繼續監聽。

注意:負責通信的socket不能無限創建,創建的數量和操作系統有關。

7.socket的構造函數

public socket(addressfamily addressfamily,sockettype sockettype,protocoltype protocoltype)

addressfamily:指定socket用來解析地址的尋址方案。例如:internetwork指示當socket使用一個ip版本4地址連接

sockettype:定義要打開的socket的類型

socket類使用protocoltype枚舉向windows sockets api通知所請求的協議

注意:

1,端口號必須在 1 和 65535之間,最好在1024以后。

2,要連接的遠程主機必須正在監聽指定端口,也就是說你無法隨意連接遠程主機。

如:

ipaddress addr = ipaddress.parse("127.0.0.1");

ipendpoint endp = new ipendpoint(addr,,9000);

服務端先綁定:serverwelcomesocket.bind(endp)

客戶端再連接:clientsocket.connect(endp)

3,一個socket一次只能連接一臺主機

4,socket關閉后無法再次使用

5,每個socket對象只能與一臺遠程主機連接。如果你想連接到多臺遠程主機,你必須創建多個socket對象。

8.socket常用類和方法

相關類:

ipaddress:包含了一個ip地址

ipendpoint:包含了一對ip地址和端口號

方法:

socket():創建一個socket

bind():綁定一個本地的ip和端口號(ipendpoint)

listen():讓socket偵聽傳入的連接吃那個病,并指定偵聽隊列容量

connect():初始化與另一個socket的連接

accept():接收連接并返回一個新的socket

send():輸出數據到socket

receive():從socket中讀取數據

close():關閉socket,銷毀連接

接下來,我們同一個簡單的服務器和客戶端通信的案例,來看下sokcet的具體用法,效果圖如下:

C#開發之Socket網絡編程TCP/IP層次模型、端口及報文等探討

 

C#開發之Socket網絡編程TCP/IP層次模型、端口及報文等探討

關鍵代碼:

服務器端代碼:

 

復制代碼 代碼如下:

 private void form1_load(object sender, eventargs e)
         {
             control.checkforillegalcrossthreadcalls = false;
         }
        private void btnlisten_click(object sender, eventargs e)
        {
            //ip地址
            ipaddress ip = ipaddress.parse(txtip.text);
           // ipaddress ip = ipaddress.any;
            //端口號
            ipendpoint point=new ipendpoint(ip,int.parse(txtport.text));
            //創建監聽用的socket
            /*
             * addressfamily.internetwork:使用 ip4地址。
sockettype.stream:支持可靠、雙向、基于連接的字節流,而不重復數據。此類型的 socket 與單個對方主機進行通信,并且在通信開始之前需要遠程主機連接。stream 使用傳輸控制協議 (tcp) protocoltype 和 internetworkaddressfamily。
protocoltype.tcp:使用傳輸控制協議。
             */
            //使用ipv4地址,流式socket方式,tcp協議傳遞數據
            socket socket=new socket(addressfamily.internetwork,sockettype.stream,protocoltype.tcp);
            //創建好socket后,必須告訴socket綁定的ip地址和端口號。
            //讓socket監聽point
            try
            {
                //socket監聽哪個端口
                socket.bind(point);
                //同一個時間點過來10個客戶端,排隊
                socket.listen(10);
                showmsg("服務器開始監聽");
                thread thread = new thread(acceptinfo);
                thread.isbackground = true;
                thread.start(socket);
            }
            catch (exception ex)
            {
               showmsg(ex.message);
            }
        }
        //記錄通信用的socket
        dictionary<string,socket> dic=new dictionary<string, socket>();
       // private socket client;
        void acceptinfo(object o)
        {
            socket socket = o as socket;
            while (true)
            {
                //通信用socket
                try
                {
                     //創建通信用的socket
                   socket  tsocket = socket.accept();
                   string point = tsocket.remoteendpoint.tostring();
                     //ipendpoint endpoint = (ipendpoint)client.remoteendpoint;
                     //string me = dns.gethostname();//得到本機名稱
                     //messagebox.show(me);
                  showmsg(point + "連接成功!");
                  cboipport.items.add(point);
                  dic.add(point, tsocket);
                     //接收消息
                     thread th = new thread(receivemsg);
                     th.isbackground = true;
                     th.start(tsocket);
                 }
                 catch (exception ex)
                 {
                     showmsg(ex.message);
                     break;
                 }
             }
         }
         //接收消息
         void receivemsg(object o)
         {
             socket client = o as socket;
             while (true)
             {
                 //接收客戶端發送過來的數據
                 try
                 {
                     //定義byte數組存放從客戶端接收過來的數據
                     byte[] buffer = new byte[1024 * 1024];
                     //將接收過來的數據放到buffer中,并返回實際接受數據的長度
                     int n = client.receive(buffer);
                     //將字節轉換成字符串
                     string words = encoding.utf8.getstring(buffer, 0, n);
                     showmsg(client.remoteendpoint.tostring() + ":" + words);
                 }
                 catch (exception ex)
                 {
                    showmsg(ex.message);
                     break;
                 }
             }
         }
         void showmsg(string msg)
         {
             txtlog.appendtext(msg+"\r\n");
         }
         private void form1_formclosing(object sender, formclosingeventargs e)
         {
             //主窗體關閉時關閉子線程
         }
         //給客戶端發送消息
         private void btnsend_click(object sender, eventargs e)
         {
             try
             {
                 showmsg(txtmsg.text);
                 string ip = cboipport.text;
                 byte[] buffer = encoding.utf8.getbytes(txtmsg.text);
                 dic[ip].send(buffer);
                 // client.send(buffer);
             }
             catch (exception ex)
             {
                showmsg(ex.message);
             }
         }

客戶端代碼:
復制代碼 代碼如下:

 socket client = new socket(addressfamily.internetwork, sockettype.stream, protocoltype.tcp);
         private void btnconnection_click(object sender, eventargs e)
         {
             //連接到的目標ip
             ipaddress ip = ipaddress.parse(txtip.text);
            //ipaddress ip = ipaddress.any;
            //連接到目標ip的哪個應用(端口號!)
            ipendpoint point=new ipendpoint(ip,int.parse(txtport.text));
            try
            {
                //連接到服務器
                client.connect(point);
                showmsg("連接成功");
                showmsg("服務器" + client.remoteendpoint.tostring());
                showmsg("客戶端:" + client.localendpoint.tostring());
                //連接成功后,就可以接收服務器發送的信息了
                thread th=new thread(receivemsg);
                th.isbackground = true;
                th.start();
            }
            catch (exception ex)
            {
                showmsg(ex.message);
            }
        }
        //接收服務器的消息
        void receivemsg()
        {
            while (true)
            {
                try
                {
                    byte[] buffer = new byte[1024 * 1024];
                    int n = client.receive(buffer);
                    string s = encoding.utf8.getstring(buffer, 0, n);
                    showmsg(client.remoteendpoint.tostring() + ":" + s);
                }
                catch (exception ex)
                {
                    showmsg(ex.message);
                    break;
                }
            }
        }
        void showmsg(string msg)
        {
            txtinfo.appendtext(msg+"\r\n");
        }
         private void btnsend_click(object sender, eventargs e)
         {
             //客戶端給服務器發消息
             if (client!=null)
             {
                 try
                 {
                    showmsg(txtmsg.text);
                     byte[] buffer = encoding.utf8.getbytes(txtmsg.text);
                     client.send(buffer);
                 }
                 catch (exception ex)
                 {
                    showmsg(ex.message);
                 }
             }
         }
         private void clientform_load(object sender, eventargs e)
         {
             control.checkforillegalcrossthreadcalls = false;
         }

好了,到這里我們對socket的討論就告一個段落了。

延伸 · 閱讀

精彩推薦
  • C#C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題實例

    這篇文章主要介紹了C#設計模式之Visitor訪問者模式解決長隆歡樂世界問題,簡單描述了訪問者模式的定義并結合具體實例形式分析了C#使用訪問者模式解決長...

    GhostRider9502022-01-21
  • C#深入解析C#中的交錯數組與隱式類型的數組

    深入解析C#中的交錯數組與隱式類型的數組

    這篇文章主要介紹了深入解析C#中的交錯數組與隱式類型的數組,隱式類型的數組通常與匿名類型以及對象初始值設定項和集合初始值設定項一起使用,需要的...

    C#教程網6172021-11-09
  • C#Unity3D實現虛擬按鈕控制人物移動效果

    Unity3D實現虛擬按鈕控制人物移動效果

    這篇文章主要為大家詳細介紹了Unity3D實現虛擬按鈕控制人物移動效果,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一...

    shenqingyu060520232410972022-03-11
  • C#C#裁剪,縮放,清晰度,水印處理操作示例

    C#裁剪,縮放,清晰度,水印處理操作示例

    這篇文章主要為大家詳細介紹了C#裁剪,縮放,清晰度,水印處理操作示例,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    吳 劍8332021-12-08
  • C#C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    C# 實現對PPT文檔加密、解密及重置密碼的操作方法

    這篇文章主要介紹了C# 實現對PPT文檔加密、解密及重置密碼的操作方法,非常不錯,具有參考借鑒價值,需要的朋友可以參考下...

    E-iceblue5012022-02-12
  • C#WPF 自定義雷達圖開發實例教程

    WPF 自定義雷達圖開發實例教程

    這篇文章主要介紹了WPF 自定義雷達圖開發實例教程,本文介紹的非常詳細,具有參考借鑒價值,需要的朋友可以參考下...

    WinterFish13112021-12-06
  • C#C#實現XML文件讀取

    C#實現XML文件讀取

    這篇文章主要為大家詳細介紹了C#實現XML文件讀取的相關代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    Just_for_Myself6702022-02-22
  • C#C#通過KD樹進行距離最近點的查找

    C#通過KD樹進行距離最近點的查找

    這篇文章主要為大家詳細介紹了C#通過KD樹進行距離最近點的查找,具有一定的參考價值,感興趣的小伙伴們可以參考一下...

    帆帆帆6112022-01-22
主站蜘蛛池模板: 斗破苍穹在线观看免费完整观看 | 久久久久9999 | 最新中文字幕第一页视频 | 黄色影院在线 | arabxxxxvideos | 日韩视频在线免费 | 日本网站在线看 | 国产91在线高潮白浆在线观看 | 国产成人av免费观看 | 深夜视频福利 | 亚洲国产超高清a毛毛片 | 欧美一级不卡视频 | 91精品国产91热久久久做人人 | 国产一级在线观看视频 | 看免费黄色大片 | 亚洲综合色视频在线观看 | 欧美日本在线播放 | 国产一级在线免费观看 | 欧美日本在线播放 | 九九热免费视频在线观看 | 精品久久久一 | 午夜丰满少妇高清毛片1000部 | 久久精热 | 欧美视频一区二区三区在线观看 | 精品一区二区三区电影 | 一区二区三区日韩精品 | 久久久久久久久久久久久久久伊免 | 色视频91| 在线成人免费网站 | 麻豆传传媒久久久爱 | 羞羞视频一区二区 | 一区二区三视频 | 成人毛片视频在线播放 | 日韩av手机在线免费观看 | lutube成人福利在线观看污 | 免费在线观看成人av | 日韩电影毛片 | 久久艹艹艹 | 91精品国产综合久久男男 | 嫩草91在线| 日韩视频一 |