西西軟件下載最安全的下載網(wǎng)站、值得信賴的軟件下載站!

首頁(yè)編程開(kāi)發(fā)C#.NET → C#開(kāi)發(fā)之Socket網(wǎng)絡(luò)編程TCP/IP層次模型、端口及報(bào)文等探討

C#開(kāi)發(fā)之Socket網(wǎng)絡(luò)編程TCP/IP層次模型、端口及報(bào)文等探討

相關(guān)軟件相關(guān)文章發(fā)表評(píng)論 來(lái)源:西西整理時(shí)間:2013/3/8 8:36:44字體大小:A-A+

作者:微冷的雨點(diǎn)擊:0次評(píng)論:1次標(biāo)簽: Socket

  • 類型:服務(wù)器區(qū)大。21KB語(yǔ)言:中文 評(píng)分:6.6
  • 標(biāo)簽:
立即下載

我們?cè)谥v解Socket編程前,先看幾個(gè)和Socket編程緊密相關(guān)的概念:

1、TCP/IP層次模型

當(dāng)然這里我們只討論重要的四層

01,應(yīng)用層(Application):應(yīng)用層是個(gè)很廣泛的概念,有一些基本相同的系統(tǒng)級(jí)TCP/IP應(yīng)用以及應(yīng)用協(xié)議,也有許多的企業(yè)應(yīng)用和互聯(lián)網(wǎng)應(yīng)用。http協(xié)議在應(yīng)用層運(yùn)行。

02,傳輸層(Tanspot):傳輸層包括UDP和TCP,UDP幾乎不對(duì)報(bào)文進(jìn)行檢查,而TCP提供傳輸保證。

03,網(wǎng)絡(luò)層(Netwok):網(wǎng)絡(luò)層協(xié)議由一系列協(xié)議組成,包括ICMP、IGMP、RIP、OSPF、IP(v4,v6)等。

04,鏈路層(Link):又稱為物理數(shù)據(jù)網(wǎng)絡(luò)接口層,負(fù)責(zé)報(bào)文傳輸。

然后我們來(lái)看下tcp層次模型圖

從上圖中可以看出,應(yīng)用程序在應(yīng)用層運(yùn)行,在傳輸層,在數(shù)據(jù)前加上了TCP頭,在

網(wǎng)絡(luò)層加上的IP頭,在數(shù)據(jù)鏈路層加上了幀。

2、端口

端口號(hào)范圍:0-65535,總共能表示65536個(gè)數(shù)。

按端口號(hào)可分為3大類

 。1)公認(rèn)端口(WellKnownPorts):從0到1023,它們緊密綁定(binding)于一些服務(wù)。通常這些端口的通訊明確表明了某種服務(wù)的協(xié)議。例如:80端口實(shí)際上總是HTTP通訊。

 。2)注冊(cè)端口(RegisteredPorts):從1024到49151。它們松散地綁定于一些服務(wù)。也就是說(shuō)有許多服務(wù)綁定于這些端口,這些端口同樣用于許多其它目的。例如:許多系統(tǒng)處理動(dòng)態(tài)端口從1024左右開(kāi)始。

 。3)動(dòng)態(tài)和/或私有端口(Dynamicand/orPrivatePorts):從49152到65535。理論上,不應(yīng)為服務(wù)分配這些端口。實(shí)際上,機(jī)器通常從1024起分配動(dòng)態(tài)端口。

3.TCP和UDP報(bào)文

下面一起來(lái)看下TCP和UDP的報(bào)文圖

從圖中我們可以看出TCP和UDP中都有校驗(yàn)和,但是在UDP報(bào)文中,一般不使用校驗(yàn)和,這樣可以加快數(shù)據(jù)傳輸?shù)乃俣,但是?shù)據(jù)的準(zhǔn)確性可能會(huì)受到影響。換句話說(shuō),Tcp協(xié)議都有校驗(yàn)和,為了保證傳輸數(shù)據(jù)的準(zhǔn)確性。

3.Socket

Socket包括Ip地址和端口號(hào)兩部分,程序通過(guò)Socket來(lái)通信,Socket相當(dāng)于操作系統(tǒng)的一個(gè)組件。Socket作為進(jìn)程之間通信機(jī)制,通常也稱作”套接字”,用于描述IP地址和端口號(hào),是一個(gè)通信鏈的句柄。說(shuō)白了,就是兩個(gè)程序通信用的。

生活案例對(duì)比:

Socket之間的通信可以類比生活中打電話的案例。任何用戶在通話之前,首先要占有一部電話機(jī),相當(dāng)于申請(qǐng)一個(gè)Socket,同時(shí)要知道對(duì)方的號(hào)碼,相當(dāng)于對(duì)方有一個(gè)固定的Socket,然后向?qū)Ψ綋芴?hào)呼叫,相當(dāng)于發(fā)出連接請(qǐng)求。假如對(duì)方在場(chǎng)并空閑,拿起 電話話筒,雙方就可以進(jìn)行通話了。雙方的通話過(guò)程,是一方向電話機(jī)發(fā)出信號(hào)和對(duì)方從電話機(jī)接收信號(hào)的過(guò)程,相當(dāng)于向socket發(fā)送數(shù)據(jù)和從socket接收數(shù)據(jù)。通話結(jié)束后,一方掛起電話機(jī),相當(dāng)于關(guān)閉socket,撤銷連接。

注意:Socket不僅可以在兩臺(tái)電腦之間通信,還可以在同一臺(tái)電腦上的兩個(gè)程序間通信。

4,端口進(jìn)階(深入)

通過(guò)IP地址確定了網(wǎng)絡(luò)中的一臺(tái)電腦后,該電腦上可能提供很多提供服務(wù)的應(yīng)用,每一個(gè)應(yīng)用都對(duì)應(yīng)一個(gè)端口。

在Internet上有很多這樣的主機(jī),這些主機(jī)一般運(yùn)行了多個(gè)服務(wù)軟件 ,同時(shí)提供幾種服務(wù),每種服務(wù)都打開(kāi)一個(gè)Socket,并綁定到一個(gè)端口上,不同的端口對(duì)應(yīng)于不同的服務(wù)(應(yīng)用程序)

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

5.Socket分類

Socket主要有兩種類型:

流式Socket

是一種面向連接的Socket,針對(duì)于面向連接的TCP服務(wù)應(yīng)用,安全,但是效率低

2,數(shù)據(jù)報(bào)式Socket

是一種無(wú)連接的Socket,對(duì)應(yīng)于無(wú)連接的UDP服務(wù)應(yīng)用,不安全,但效率高

6. Socket一般應(yīng)用模式(服務(wù)器端和客戶端)

服務(wù)器端的Socket(至少需要兩個(gè))

01.一個(gè)負(fù)責(zé)接收客戶端連接請(qǐng)求(但不負(fù)責(zé)與客戶端通信)

02.每成功接收到客戶端的連接便在服務(wù)器端產(chǎn)生一個(gè)對(duì)應(yīng)的復(fù)雜通信的Socket

021.在接收到客戶端連接時(shí)創(chuàng)建

022. 為每個(gè)連接成功的客戶端請(qǐng)求在服務(wù)器端都創(chuàng)建一個(gè)對(duì)應(yīng)的Socket(負(fù)責(zé)和客戶端通信)

客戶端的Socket

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

通過(guò)創(chuàng)建一個(gè)Socket對(duì)象來(lái)初始化一個(gè)到服務(wù)器端的TCP連接

通過(guò)上圖,我們可以看出,首先服務(wù)器會(huì)創(chuàng)建一個(gè)負(fù)責(zé)監(jiān)聽(tīng)的socket,然后客戶端通過(guò)socket連接到服務(wù)器指定端口,最后服務(wù)器端負(fù)責(zé)監(jiān)聽(tīng)的socket,監(jiān)聽(tīng)到客戶端有連接過(guò)來(lái)了,就創(chuàng)建一個(gè)負(fù)責(zé)和客戶端通信的socket。

下面我們來(lái)看下Socket更具體的通信過(guò)程:

Socket的通訊過(guò)程

服務(wù)器端:

01,申請(qǐng)一個(gè)socket

02,綁定到一個(gè)IP地址和一個(gè)端口上

03,開(kāi)啟偵聽(tīng),等待接收連接

客戶端:

01,申請(qǐng)一個(gè)socket

02,連接服務(wù)器(指明IP地址和端口號(hào))

服務(wù)器端接收到連接請(qǐng)求后,產(chǎn)生一個(gè)新的socket(端口大于1024)與客戶端建立連接并進(jìn)行通信,原監(jiān)聽(tīng)socket繼續(xù)監(jiān)聽(tīng)。

注意:負(fù)責(zé)通信的Socket不能無(wú)限創(chuàng)建,創(chuàng)建的數(shù)量和操作系統(tǒng)有關(guān)。

7.Socket的構(gòu)造函數(shù)

Public Socket(AddressFamily addressFamily,SocketType socketType,ProtocolType protocolTYpe)

AddressFamily:指定Socket用來(lái)解析地址的尋址方案。例如:InterNetWork指示當(dāng)Socket使用一個(gè)IP版本4地址連接

SocketType:定義要打開(kāi)的Socket的類型

Socket類使用ProtocolType枚舉向Windows Sockets API通知所請(qǐng)求的協(xié)議

注意:

1,端口號(hào)必須在 1 和 65535之間,最好在1024以后。

2,要連接的遠(yuǎn)程主機(jī)必須正在監(jiān)聽(tīng)指定端口,也就是說(shuō)你無(wú)法隨意連接遠(yuǎn)程主機(jī)。

如:

IPAddress addr = IPAddress.Parse("127.0.0.1");

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

服務(wù)端先綁定:serverWelcomeSocket.Bind(endp)

客戶端再連接:clientSocket.Connect(endp)

3,一個(gè)Socket一次只能連接一臺(tái)主機(jī)

4,Socket關(guān)閉后無(wú)法再次使用

5,每個(gè)Socket對(duì)象只能與一臺(tái)遠(yuǎn)程主機(jī)連接。如果你想連接到多臺(tái)遠(yuǎn)程主機(jī),你必須創(chuàng)建多個(gè)Socket對(duì)象。

8.Socket常用類和方法

相關(guān)類:

IPAddress:包含了一個(gè)IP地址

IPEndPoint:包含了一對(duì)IP地址和端口號(hào)

方法:

Socket():創(chuàng)建一個(gè)Socket

Bind():綁定一個(gè)本地的IP和端口號(hào)(IPEndPoint)

Listen():讓Socket偵聽(tīng)傳入的連接吃那個(gè)病,并指定偵聽(tīng)隊(duì)列容量

Connect():初始化與另一個(gè)Socket的連接

Accept():接收連接并返回一個(gè)新的Socket

Send():輸出數(shù)據(jù)到Socket

Receive():從Socket中讀取數(shù)據(jù)

Close():關(guān)閉Socket,銷毀連接

接下來(lái),我們同一個(gè)簡(jiǎn)單的服務(wù)器和客戶端通信的案例,來(lái)看下Sokcet的具體用法,效果圖如下:


關(guān)鍵代碼:

服務(wù)器端代碼:

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             //端口號(hào)
 22 
 23             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));
 24 
 25             //創(chuàng)建監(jiān)聽(tīng)用的Socket
 26 
 27             /*
 28 
 29              * AddressFamily.InterNetWork:使用 IP4地址。
 30 
 31 SocketType.Stream:支持可靠、雙向、基于連接的字節(jié)流,而不重復(fù)數(shù)據(jù)。此類型的 Socket 與單個(gè)對(duì)方主機(jī)進(jìn)行通信,并且在通信開(kāi)始之前需要遠(yuǎn)程主機(jī)連接。Stream 使用傳輸控制協(xié)議 (Tcp) ProtocolType 和 InterNetworkAddressFamily。
 32 
 33 ProtocolType.Tcp:使用傳輸控制協(xié)議。
 34 
 35              */
 36 
 37             //使用IPv4地址,流式socket方式,tcp協(xié)議傳遞數(shù)據(jù)
 38 
 39             Socket socket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
 40 
 41             //創(chuàng)建好socket后,必須告訴socket綁定的IP地址和端口號(hào)。
 42 
 43             //讓socket監(jiān)聽(tīng)point
 44 
 45             try
 46 
 47             {
 48 
 49                 //socket監(jiān)聽(tīng)哪個(gè)端口
 50 
 51                 socket.Bind(point);
 52 
 53                 //同一個(gè)時(shí)間點(diǎn)過(guò)來(lái)10個(gè)客戶端,排隊(duì)
 54 
 55                 socket.Listen(10);
 56 
 57                 ShowMsg("服務(wù)器開(kāi)始監(jiān)聽(tīng)");
 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         //記錄通信用的Socket
 80 
 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                 //通信用socket
 96 
 97                 try
 98 
 99                 {
100 
101                     //創(chuàng)建通信用的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();//得到本機(jī)名稱
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                 //接收客戶端發(fā)送過(guò)來(lái)的數(shù)據(jù)
156 
157                 try
158 
159                 {
160 
161                     //定義byte數(shù)組存放從客戶端接收過(guò)來(lái)的數(shù)據(jù)
162 
163                     byte[] buffer = new byte[1024 * 1024];
164 
165                     //將接收過(guò)來(lái)的數(shù)據(jù)放到buffer中,并返回實(shí)際接受數(shù)據(jù)的長(zhǎng)度
166 
167                     int n = client.Receive(buffer);
168 
169                     //將字節(jié)轉(zhuǎn)換成字符串
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             //主窗體關(guān)閉時(shí)關(guān)閉子線程
210 
211           
212 
213         }
214 
215         //給客戶端發(fā)送消息
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             //連接到的目標(biāo)IP
  8 
  9             IPAddress ip = IPAddress.Parse(txtIP.Text);
 10 
 11             //IPAddress ip = IPAddress.Any;
 12 
 13             //連接到目標(biāo)IP的哪個(gè)應(yīng)用(端口號(hào)!)
 14 
 15             IPEndPoint point=new IPEndPoint(ip,int.Parse(txtPort.Text));
 16 
 17             try
 18 
 19             {
 20 
 21                 //連接到服務(wù)器
 22 
 23                 client.Connect(point);
 24 
 25                 ShowMsg("連接成功");
 26 
 27                 ShowMsg("服務(wù)器" + client.RemoteEndPoint.ToString());
 28 
 29                 ShowMsg("客戶端:" + client.LocalEndPoint.ToString());
 30 
 31                 //連接成功后,就可以接收服務(wù)器發(fā)送的信息了
 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         //接收服務(wù)器的消息
 52 
 53         void ReceiveMsg()
 54 
 55         {
 56 
 57             while (true)
 58 
 59             {
 60 
 61                 try
 62 
 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             //客戶端給服務(wù)器發(fā)消息
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         }

好了,到這里我們對(duì)Socket的討論就告一個(gè)段落了。

    相關(guān)評(píng)論

    閱讀本文后您有什么感想? 已有人給出評(píng)價(jià)!

    • 8 喜歡喜歡
    • 3 頂
    • 1 難過(guò)難過(guò)
    • 5 囧
    • 3 圍觀圍觀
    • 2 無(wú)聊無(wú)聊

    熱門評(píng)論

    最新評(píng)論

    第 1 樓 浙江杭州鐵通 網(wǎng)友 客人 發(fā)表于: 2015/5/21 17:24:19
    特別贊,很不錯(cuò)的文章。

    支持( 0 ) 蓋樓(回復(fù))

    發(fā)表評(píng)論 查看所有評(píng)論(1)

    昵稱:
    表情: 高興 可 汗 我不要 害羞 好 下下下 送花 屎 親親
    字?jǐn)?shù): 0/500 (您的評(píng)論需要經(jīng)過(guò)審核才能顯示)