C# Socket網絡編程精華篇

我們在講解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層次模型圖

?

? ? ?從上圖中可以看出,應用程序在應用層運行,在傳輸層,在數據前加上了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的報文圖

?

? ? ? 從圖中我們可以看出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主要有兩種類型:

  1. 流式Socket

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

? ? ?2,數據報式Socket

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

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

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

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

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

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

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

? ? 客戶端的Socket

  1. 必須指定要連接的服務器地址和端口
  2. 通過創建一個Socket對象來初始化一個到服務器端的TCP連接

?

? ? ? 通過上圖,我們可以看出,首先服務器會創建一個負責監聽的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的具體用法,效果圖如下:

?

關鍵代碼:

服務器端代碼:

復制代碼
  1 private void Form1_Load(object sender, EventArgs e)2 3         {4 5             Control.CheckForIllegalCrossThreadCalls = false;6 7         }8 9  10 11         private void btnListen_Click(object sender, EventArgs e)12 13         {14 15             //ip地址16 17             IPAddress ip = IPAddress.Parse(txtIP.Text);18 19            // IPAddress ip = IPAddress.Any;20 21             //端口號22 23             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));24 25             //創建監聽用的Socket26 27             /*28 29              * AddressFamily.InterNetWork:使用 IP4地址。30 31 SocketType.Stream:支持可靠、雙向、基于連接的字節流,而不重復數據。此類型的 Socket 與單個對方主機進行通信,并且在通信開始之前需要遠程主機連接。Stream 使用傳輸控制協議 (Tcp) ProtocolType 和 InterNetworkAddressFamily。32 33 ProtocolType.Tcp:使用傳輸控制協議。34 35              */36 37             //使用IPv4地址,流式socket方式,tcp協議傳遞數據38 39             Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);40 41             //創建好socket后,必須告訴socket綁定的IP地址和端口號。42 43             //讓socket監聽point44 45             try46 47             {48 49                 //socket監聽哪個端口50 51                 socket.Bind(point);52 53                 //同一個時間點過來10個客戶端,排隊54 55                 socket.Listen(10);56 57                 ShowMsg("服務器開始監聽");58 59                 Thread thread = new Thread(AcceptInfo);60 61                 thread.IsBackground = true;62 63                 thread.Start(socket);64 65             }66 67             catch (Exception ex)68 69             {70 71                72 73                ShowMsg(ex.Message);74 75             }76 77         }78 79         //記錄通信用的Socket80 81         Dictionary<string,Socket> dic=new Dictionary<string, Socket>();82 83        // private Socket client;84 85         void AcceptInfo(object o)86 87         {88 89             Socket socket = o as Socket;90 91             while (true)92 93             {94 95                 //通信用socket96 97                 try98 99                 {
100 
101                     //創建通信用的Socket
102 
103                   Socket  tSocket = socket.Accept();
104 
105                   string point = tSocket.RemoteEndPoint.ToString();
106 
107                     //IPEndPoint endPoint = (IPEndPoint)client.RemoteEndPoint;
108 
109                     //string me = Dns.GetHostName();//得到本機名稱
110 
111                     //MessageBox.Show(me);
112 
113                  ShowMsg(point + "連接成功!");
114 
115                  cboIpPort.Items.Add(point);
116 
117                  dic.Add(point, tSocket);
118 
119                     //接收消息
120 
121                     Thread th = new Thread(ReceiveMsg);
122 
123                     th.IsBackground = true;
124 
125                     th.Start(tSocket);
126 
127                 }
128 
129                 catch (Exception ex)
130 
131                 {
132 
133                     ShowMsg(ex.Message);
134 
135                     break;
136 
137                 }
138 
139             }
140 
141         }
142 
143         //接收消息
144 
145         void ReceiveMsg(object o)
146 
147         {
148 
149             Socket client = o as Socket;
150 
151             while (true)
152 
153             {
154 
155                 //接收客戶端發送過來的數據
156 
157                 try
158 
159                 {
160 
161                     //定義byte數組存放從客戶端接收過來的數據
162 
163                     byte[] buffer = new byte[1024 * 1024];
164 
165                     //將接收過來的數據放到buffer中,并返回實際接受數據的長度
166 
167                     int n = client.Receive(buffer);
168 
169                     //將字節轉換成字符串
170 
171                     string words = Encoding.UTF8.GetString(buffer, 0, n);
172 
173                   
174 
175                     ShowMsg(client.RemoteEndPoint.ToString() + ":" + words);
176 
177                 }
178 
179                 catch (Exception ex)
180 
181                 {
182 
183                    ShowMsg(ex.Message);
184 
185                     break;
186 
187                 }
188 
189             }
190 
191         }
192 
193  
194 
195         void ShowMsg(string msg)
196 
197         {
198 
199             txtLog.AppendText(msg+"\r\n");
200 
201         }
202 
203  
204 
205         private void Form1_FormClosing(object sender, FormClosingEventArgs e)
206 
207         {
208 
209             //主窗體關閉時關閉子線程
210 
211           
212 
213         }
214 
215         //給客戶端發送消息
216 
217         private void btnSend_Click(object sender, EventArgs e)
218 
219         {
220 
221             try
222 
223             {
224 
225                 ShowMsg(txtMsg.Text);
226 
227                 string ip = cboIpPort.Text;
228 
229                 byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);
230 
231                 dic[ip].Send(buffer);
232 
233                 // client.Send(buffer);
234 
235             }
236 
237             catch (Exception ex)
238 
239             {
240 
241                ShowMsg(ex.Message);
242 
243             }
244 
245  
246 
247         }
復制代碼

?

客戶端代碼:

復制代碼
  1 Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);2 3         private void btnConnection_Click(object sender, EventArgs e)4 5         {6 7             //連接到的目標IP8 9             IPAddress ip = IPAddress.Parse(txtIP.Text);10 11             //IPAddress ip = IPAddress.Any;12 13             //連接到目標IP的哪個應用(端口號!)14 15             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));16 17             try18 19             {20 21                 //連接到服務器22 23                 client.Connect(point);24 25                 ShowMsg("連接成功");26 27                 ShowMsg("服務器" + client.RemoteEndPoint.ToString());28 29                 ShowMsg("客戶端:" + client.LocalEndPoint.ToString());30 31                 //連接成功后,就可以接收服務器發送的信息了32 33                 Thread th=new Thread(ReceiveMsg);34 35                 th.IsBackground = true;36 37                 th.Start();38 39             }40 41             catch (Exception ex)42 43             {44 45                 ShowMsg(ex.Message);46 47             }48 49         }50 51         //接收服務器的消息52 53         void ReceiveMsg()54 55         {56 57             while (true)58 59             {60 61                 try62 63                 {64 65                     byte[] buffer = new byte[1024 * 1024];66 67                     int n = client.Receive(buffer);68 69                     string s = Encoding.UTF8.GetString(buffer, 0, n);70 71                     ShowMsg(client.RemoteEndPoint.ToString() + ":" + s);72 73                 }74 75                 catch (Exception ex)76 77                 {78 79                     ShowMsg(ex.Message);80 81                     break;82 83                 }84 85             }86 87           88 89         }90 91  92 93         void ShowMsg(string msg)94 95         {96 97             txtInfo.AppendText(msg+"\r\n");98 99         }
100 
101  
102 
103         private void btnSend_Click(object sender, EventArgs e)
104 
105         {
106 
107             //客戶端給服務器發消息
108 
109             if (client!=null)
110 
111             {
112 
113                 try
114 
115                 {
116 
117                    ShowMsg(txtMsg.Text);
118 
119                     byte[] buffer = Encoding.UTF8.GetBytes(txtMsg.Text);
120 
121                     client.Send(buffer);
122 
123                 }
124 
125                 catch (Exception ex)
126 
127                 {
128 
129                    ShowMsg(ex.Message);
130 
131                 }
132 
133             }
134 
135            
136 
137         }
138 
139  
140 
141         private void ClientForm_Load(object sender, EventArgs e)
142 
143         {
144 
145             Control.CheckForIllegalCrossThreadCalls = false;
146 
147         }
復制代碼

轉載于:https://www.cnblogs.com/asdyzh/p/9839775.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/250411.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/250411.shtml
英文地址,請注明出處:http://en.pswp.cn/news/250411.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Luogu1443 馬的遍歷【STL通俗BFS】

喜聞樂見當做BFS的STL模板做了 qwq我這樣的蒟蒻也就只能發發模板題 #include<cstdio> #include<cstring> #include<cmath> #include<queue> using namespace std; struct xy{int x,y; }node,top; int dx[8]{1,1,2,2,-1,-1,-2,-2}; int dy[8]{2,-2,1,-1…

javascript --- [虛擬DOM] 初始化 實現

說明 本篇主要說明為什么要使用虛擬DOM技術,以及如何實現簡單的虛擬dom您將會學到: 1.原生JS對DOM的操作 2.虛擬DOM的相關概念 3.DIFF算法的基礎概念 為什么提出 -> DOM操作慢 我們使用createElement屬性來創建一個最常見的div,看看一個最常見的DOM有多少個屬性 <scri…

模塊單元學習筆記(日志記錄模塊os模塊sys)

一、日志記錄模塊 Logging 默認情況下&#xff0c;logging將日志打印到屏幕&#xff0c;日志級別大小關系為&#xff1a;CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET&#xff0c;當然也可以自己定義日志級別。 DEBUG&#xff1a;詳細的信息,通常只出現…

webpack --- [4.x]你能看懂的webpack項目初始化

說明: 本篇文章主要做如下事情: 創建一個基本的webpack4.x 項目[報錯]: The mode option has not been set, webpack will fallback to production for this value[報錯]: ERROR in Entry module not found: Error: Can not resolve ./src in D:\L-react\HeiMa\01.webpack-ba…

tomcat8 進入不了Manager App 界面 403 Access Denied

準備 1.注釋掉context.xml中的value屬性 使用下面的命令&#xff1a; vim /usr/local/tomcats/tomcat-daily/webapps/manager/META-INF/context.xml 注釋掉其中value節點 2.修改tomcat-users.xml文件 加入下面的配置 <role rolename"manager-gui" /><role …

SCRIPT70: 沒有權限

主要原因&#xff1a;iframe安全而引發的問題&#xff0c;瀏覽器中js是沒有垮域訪問的權限的。如果用到iframe首先確保不垮域&#xff0c;或者不用iframe以繞開這個問題。 另外在jquery的早期版本中如&#xff1a;jquery-1.9.1.js $(#iframeWeb).attr(src, url);出現這樣的問題…

webpack --- 在項目中使用React

說明: 分為2步: 首先導入react 和 react-dom:保證了虛擬DOM的創建和使用使用babel轉碼器: 由于DOM結構太多,每次使用React.createElement創建虛擬DOM會給開發帶來很大壓力,因此采用html的寫法,通過babel轉碼器轉換成React語法,可以很大程度上提高開發效率 項目源代碼 在項目…

js改變select下拉框默認選擇的option

比較簡單&#xff0c;記錄一下 var obj document.getElementById("fun"); obj.options[0].selected true; 轉載于:https://www.cnblogs.com/vicF/p/9844028.html

vue攔截器實現統一token,并兼容IE9驗證

項目中使用vue搭建前端頁面&#xff0c;并通過axios請求后臺api接口&#xff0c;完成數據交互。如果驗證口令token寫在在每次的接口中&#xff0c;也是個不小的體力活&#xff0c;而且也不靈活。這里分享使用vue自帶攔截器&#xff0c;給每次請求的頭部添加token&#xff0c;而…

Android Studio --- [學習筆記]Button、TextView、EditText

說明 源代碼為了更全面的了解RN,先熟悉一下Android開發 第1章 Android 初體驗 1.1 Android開發概述 Android是Google開發的操作系統Android開發是移動應用開發的表現形式之一(Android、IOS、H5 App、Native H5、 RN、ionic、MUI…) 1.2 Android開發工具 Android Studio為…

BZOJ2154: Crash的數字表格 BZOJ2693: jzptab

【傳送門&#xff1a;BZOJ2154&BZOJ2693】 簡要題意&#xff1a; 給出n,m&#xff0c;求$\sum_{i1}^{n}\sum_{j1}^{m}LCM(i,j)$ 題解&#xff1a; 莫比烏斯反演&#xff08;因為BZOJ2693是多組數據&#xff0c;數據強一點&#xff0c;所以代碼用BZOJ2693的&#xff09; 設n…

對于數據庫表排他更新的理解

1. 首先任何應用程序都只能有一個服務端&#xff0c;服務端共享數據給多個客戶端訪問。 (ア) 客戶端從服務端取得相應的數據。 (イ) 或者更新、刪除服務端的內容。 2. 當客戶端A進入服務端方法更新數據庫&#xff0c;服務端方法將被鎖定。其它客戶端在訪問該方法時&#xff0c…

Angular 路由守衛

1. 路由 Angular路由: 可以控制頁面跳轉&#xff1b;可以在多視圖間切換&#xff1b; 2. 路由守衛 Angular路由守衛&#xff1a; 在進入或離開某路由時&#xff0c;用于判斷是否可以離開、進入某路由&#xff1b;&#xff1b;&#xff1b; return true 代表可以進入當前路由&am…

Vue頁面手動刷新,導航欄激活項還原到初始狀態問題解決方案

場景描述&#xff1a;在頁面中存在頂部導航和左側導航&#xff0c;左側導航和右側內容區使用了命名視圖實現&#xff0c;點擊左側導航的鏈接時&#xff0c;右側內容區相應顯示不同組件內容。問題&#xff1a;在當前鏈接手動刷新瀏覽器&#xff08;例如&#xff1a;瀏覽器地址為…

Android Studio --- [學習筆記]RadioButton、CheckBox、ImageView、ListView、TCP的三次握手

說明 源代碼在2.x里有TCP的三次揮手與四次握手,先對它進行簡單的回答(百度).預計在下一篇里,會繼續說明TCP接上一篇: Android Studio — > [學習筆記]Button、TextView、EditText 2.5 RadioButton 常用屬性自定義樣式監聽事件 2.5.1 新建按鈕,并跳轉到相應的活動頁面 1.…

洛谷3171 網絡吞吐量(網絡流)

t開成n結果cur賦值的時候也只賦值到t令人智熄 【題目分析】 好吧我承認這個錯誤真的呵呵。。。。。。。。 題目有那~~~~~么長&#xff0c;然后畫畫圖這道題就基本看出正解了&#xff0c;再一看數據范圍&#xff0c;n<500簡直良心&#xff0c;好了&#xff0c;網絡流沒得跑了…

DIV+CSS布局的優勢和弊端

DIVCSS的優勢1、符合W3C標準。這保證您的網站不會因為將來網絡應用的升級而被淘汰。2、對瀏覽者和瀏覽器更具親和力。由于CSS富含豐富的樣式&#xff0c;使頁面更加靈活性&#xff0c;它可以根據不同的瀏覽器&#xff0c;而達到顯示效果的統一和不變形。這樣就支持瀏覽器的向后…

Android Studio --- [學習筆記]TCP(第2彈)、GridView、ScrollView

說明 這篇主要接上一篇Android Studio — > [學習筆記]RadioButton、CheckBox、ImageView、ListView、TCP的三次握手對上面回答的細解,并用JS偽代碼,對TCP三次握手和四次揮手的簡單實現.Android的基本了解到此篇結束,后續會根據具體情況深度學習. 2.y TCP的三次握手和四次揮…

MySQL中varchar最大長度是多少

一. varchar存儲規則&#xff1a; 4.0版本以下&#xff0c;varchar(20)&#xff0c;指的是20字節&#xff0c;如果存放UTF8漢字時&#xff0c;只能存6個&#xff08;每個漢字3字節&#xff09; 5.0版本以上&#xff0c;varchar(20)&#xff0c;指的是20字符&#xff0c;無論存放…

bzoj 1232: [Usaco2008Nov]安慰奶牛cheer【最小生成樹】

有趣 每條邊在算答案的時候被算了二倍的邊權值加上兩個端點的權值&#xff0c;然后睡覺點額外加一次 所以可以用這個權做MST&#xff0c;然后加上點權最小的點 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N1…