利用TCP和UDP協議,實現基於Socket的小聊天程序(初級版)


TCP

TCP (Transmission Control Protocol)屬於傳輸層協議。其中TCP提供IP環境下的數據可靠傳輸,它提供的服務 包括數據流傳送、可靠性、有效流控、全雙工操作和多路復用。通過面向連接、端到端和可靠的數據包發送。通俗說,TCP支持的應用協議主要有:Telnet、FTP、SMTP等

TCP是面向對象的連接,是安全可靠的,是基於連接的協議,也就是說,在正式收發數據前,必須和對方建立可靠的連接。一個TCP連接必須要經過三次“對話”才能建立起來,其中的過程非常復雜,我 們這里只做簡單、形象的介紹,你只要做到能夠理解這個過程即可。我們來看看這三次對話的簡單過程:主機A向主機B發出連接請求數據包:“我想給你發數據, 可以嗎?”,這是第一次對話;主機B向主機A發送同意連接和要求同步(同步就是兩台主機一個在發送,一個在接收,協調工作)的數據包:“可以,你什么時候 發?”,這是第二次對話;主機A再發出一個數據包確認主機B的要求同步:“我現在就發,你接着吧!”,這是第三次對話。三次“對話”的目的是使數據包的發 送和接收同步,經過三次“對話”之后,主機A才向主機B正式發送數據。

 

首先我們來看看用TCP實現聊天程序

實現聊天程序我們需要一個服務端一個客戶端來模擬實現,我們首先來建立服務器端,直接貼代碼,如下:

建立Socket並綁定IP和端口
 1             // 首先建立一個套接字(服務器端)
 2              Socket socketServer =  new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
 3              // 將套接字綁定到本地的IP和端口
 4              IPEndPoint endPoint =  new IPEndPoint(IPAddress.Any,  9999);
 5              // 綁定套接字
 6              socketServer.Bind(endPoint);
 7              // 輸出語句 服務已經啟動
 8              Console.WriteLine( " =====TCP Server Is OK======\r\n ===IP: " + endPoint.Address +  "   Port: " + endPoint.Port+ " === ");
 9              // 開始監聽
10              socketServer.Listen( 10);
11              //接受消息並 返回的新的套接字對象
12              Socket sk = socketServer.Accept();

簡要介紹下個別變量,方法的作用:

socketServer:實例化一個服務端的Socket實例

endPoint:網絡終結點,定義了IP和Port

Bind方法:用於將Socket實例綁定到該網絡終結點上

Listen方法:監聽端口,參數為監聽序列的長度

Accept方法:接受通信,返回一個新的Socket對象,然后之后的通信就交由該新的對象來進行,socketServer就相當於公司的前台,只負責接待,具體的事務是通過它交由其他人來執行(個人理解)

 

然后是服務器端接受數據的代碼,如下:

服務器端接受數據
 1              // 接受數據
 2 
 3               // 新建一個字節數組
 4               byte[] recveMsg= new  byte[ 1024* 1024];
 5              // 使用receive方法接受發送到服務器端的數據
 6               int bytes = sk.Receive(recveMsg,SocketFlags.None);
 7              // 將數據進行編碼
 8               string receive = System.Text.Encoding.UTF8.GetString(recveMsg,  0, bytes);
 9              // 將信息打印到控制台
10              Console.WriteLine(receive);

簡要解釋下個別變量的作用:

recveMsg:這是一個字節數組,因為在接受數據時,我們需要將接收到的數據存放到字節數組中,所以我們要首先定義一個字節數組,這里我給了它1024*1024的大小

bytes:這是一個int型變量,作用就是用來接收Socket用Receive接受到數據的實際長度,但為什么我們需要這個變量呢,因為在后一行代碼中,我們需要將字節數組轉換為字符串來進行輸出,如果沒有這個變量來定義大小,我們每次都會把1024*1024的字節長度轉換成字符串,所以往往有時候接收到的長度沒有1024*1024大小,

因此會造成無用的轉換。

 

然后就是發送數據,貼上代碼:

服務器端發送數據
 1              // 發送數據
 2 
 3               // 實例化發送的信息
 4               string message= " Hello Clinet,My Name Is HolyKnight_Server ";
 5              // 將字符串轉換成字節數組
 6               byte[] sendMsg = System.Text.Encoding.UTF8.GetBytes(message);
 7              // 發送數據
 8               int sendBytes = sk.Send(sendMsg, SocketFlags.None);
 9 
10              // 關閉套接字
11              socketServer.Close();
12 
13             Console.ReadKey();

簡要的解釋下個別變量的作用:

message:這個很顯然,我們用message定義了一個字符串,來模擬要發送的數據

sendMsg:剛上面說了,接受數據時我們會用一個字節數組來接受,然后將數據存到該數組中,同理,發送也一樣,發送的數據也要求是字節數組,所以我們同樣定義一個字節數組來存放要發送的數據。

sendBytes:同樣一個int型的變量,來接受Socket用Send發送數據的實際長度(大小)。

 

好,這樣呢,我們的服務器端就搭建好了,這時我們需要一個客戶端,所以下面我們來創建客戶端

同樣,首先也要新建一個Socket,並綁定IP和Port,再連接到遠程主機,代碼如下:

客戶端Socket
1              // 新建一個套接字(客戶端)
2              Socket socketClient =  new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
3              // 設置與遠程主機連接的網絡節點
4              IPEndPoint endPoint =  new IPEndPoint(IPAddress.Parse( " 127.0.0.1 "),  9999);
5              // 與遠程主機建立連接
6              socketClient.Connect(endPoint);

 簡要解釋下個別變量,方法的作用:

socketClient:實例化一個客戶端的Socket對象

endPoint:網絡終結點,這里用了127.0.0.1這個IP地址(回環地址),端口號必須和服務器端的相同

Connect方法:已經定義好了Socket對象和網絡終結點了,這里就用Connect方法來實現和遠程主機建立連接了

 

同樣客戶端也要進行發送和接受數據,由於兩個方法和服務器端端的收發數據方法一致,這里就不再重復贅述了,直接貼上代碼:

發送數據:

客戶端發送數據
1              // 發送數據
2               string sendMsg =  " Hello Server,My Name Is HolyKnight_Client ";
3              byte[] sendBytes = System.Text.Encoding.UTF8.GetBytes(sendMsg);
4              int bytes = socketClient.Send(sendBytes, SocketFlags.None);
客戶端接受數據
1              // 接受數據
2               byte[] receiveMsg =  new  byte[ 1024 *  1024];
3              int receiveBytes = socketClient.Receive(receiveMsg, SocketFlags.None);
4              string Message = System.Text.Encoding.UTF8.GetString(receiveMsg,  0, receiveBytes);
5             Console.WriteLine(Message);

接受數據:

客戶端接受數據
1              // 接受數據
2               byte[] receiveMsg =  new  byte[ 1024 *  1024];
3              int receiveBytes = socketClient.Receive(receiveMsg, SocketFlags.None);
4              string Message = System.Text.Encoding.UTF8.GetString(receiveMsg,  0, receiveBytes);
5             Console.WriteLine(Message);

 

 

 這樣,我們的客戶端也就搭建好了,所以至此,我們的小聊天程序的客戶端和服務器端都搭建完畢,可以來運行看效果了,運行時,我們必須首先運行服務器端,然后再開啟客戶端進行遠程連接,首先開啟服務器端:顯示【TCP Server Is OK】並顯示了IP和Port,表示服務器端服務已成功開啟,圖如下:

 接下來運行客戶端程序,客戶端已開啟就會連上服務器端,並接受到服務器發送過來的數據,運行效果如圖:

 

此時,服務器端也應該接受到了來自客戶端的數據,查看,果然收到了數據,如圖:

 

至此,一個基於TCP的Socket的簡單通信就完成了,,,,下面我們要開看看,用UDP同樣來實現這個效果。。。

 

 UDP

 

UDP 是User Datagram Protocol的簡稱, 中文名是用戶數據報協議,是 一種無連接的傳輸層協議,提供面向事務的簡單不可靠信息傳送服務,與TCP不同的是,UDP是面向無連接的,它沒有TCP傳輸前的“三次握手”的機制,是一種不可靠的傳輸機制。。

我們再來看看用UDP實現小聊天程序吧,,,

同TCP一樣,UDP同樣需要一個服務器端和一個客戶端來模擬對話,我們就用兩個控制台應用程序實現,首先我們來搭建服務器端,貼上代碼:

UDP服務器端Socket
             // 第一步 定義一個Socket
            Socket socketServer =  new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            
             // 第二步 設置一個網絡節點
            IPEndPoint endPoint =  new IPEndPoint(IPAddress.Any,  8888);
            
             // 將socketServer綁定到網絡節點上
            socketServer.Bind(endPoint);

             // 【Tcp的時候需要監聽 但DUP不需要監聽】
            
// socketServer.Listen(10);            

// 輸出一句話 提示服務已開啟
            Console.WriteLine( " ===UDP Server Is OK===\r\n IP: " + endPoint.Address +  "   Port: " + endPoint.Port);

【解釋】:與TCP一樣,實例化一個Socket對象,然后新建一個網絡終結點,並指定IP和Port,然后將Socket對象綁定到該終結點上

【不同】:由於UDP是面向無連接的,所以在UDP中並不需要監聽機制

 

 大家還記得上面TCP接受到通信時是怎樣處理的么??是的,Accept方法返回了一個新的Socket對象,之后由該對象進行通信,那UDP呢?先看代碼吧。。

新網絡地址
1             // 定義要發送的計算機的地址 端口為0的時候表示系統分配端口
2              IPEndPoint sender =  new IPEndPoint(IPAddress.Any,  0);
3              // 建立一個網絡地址
4              EndPoint Remote = (EndPoint)sender;

 原來在UDP中,我們首先會實例化一個新的網絡地址(該地址的IP為任意IP,端口號為0,表示由系統分配端口),在收發數據時,將該網絡地址引用到主機的網絡地址上,之后我們就可以通過這個網絡地址來收發數據了

接下來開始收發數據,首先接受數據的代碼:

UDP接受數據
1             // 第三步 通過套接字收發報文
2               byte[] data= new  byte[ 1024* 1024];
3              // 接受數據報文到緩沖區 並存儲終結點
4               int receive = socketServer.ReceiveFrom(data, ref Remote);
5              // 打印到控制台
6              Console.WriteLine( " Message Received From {0} ", Remote.ToString());
7             Console.WriteLine(System.Text.Encoding.UTF8.GetString(data,  0, receive));

【解釋】:同樣,我們在接受數據的時候要將數據存放到一個字節數組中,所以我們仍然會定義一個字節數組data

【不同】:1).我們除了存放接收到的數據,我們還要將遠程主機的通信節點信息存儲下來,注意參數類型ref ,為引用類型,也就是將該類型用指針指向了主機節點類型的地址。

                2).接受數據的方法,TCP中為Receive方法,UDP中為ReceiveFrom方法

 

接下來看看發送數據的代碼,如下:

UDP發送數據
1              // 要發送的數據
2               string sendMsg =  " Hello Client,My Name is HolyKnight_UdpServer ";
3              // 將數據轉換成字節數組
4              data = System.Text.Encoding.UTF8.GetBytes(sendMsg);
5              // 將數據發送到指定的網絡地址
6              socketServer.SendTo(data, SocketFlags.None, Remote);

【解釋】:我們發送數據時,定義了一個字符串作為模擬發送數據,當然,它發送數據也是要求為字節數組,同樣的我們做了轉換

【不同】:1).在TCP中我們發送數據,直接將字節數組作為參數發送就可以了,但在UDP中,我們多了一個參數,就是我們之前指定的新的終結點,由於在前面的接收數據代碼中,我們已經用

該參數保存了遠程主機通信節點的信息了,所以我們在這里發送數據的時候,直接將數據發送到該網絡節點就可以了

                2).TCP中的發送方法為Send,而在UDP中為SendTo。

 

同時我們還實現循環收發數據,思路很簡單,就是把收發數據放在了一個死循環中,代碼如下:

循環收發數據
 1              int count =  0;
 2              try
 3             {
 4                  // 循環收發數據
 5                   while ( true)
 6                 {
 7                      // 接受數據
 8                      data =  new  byte[ 1024 *  1024];
 9                      // 從端點接受數據
10                      receive = socketServer.ReceiveFrom(data,  ref Remote);
11                      // 打印到控制台
12                      Console.WriteLine( " The Client Say: " + System.Text.Encoding.UTF8.GetString(data,  0, receive));
13                     count++;
14 
15                      // 發送數據
16                       string reply =  " 這是服務器的第 " + count.ToString() +  " 次回復 ";
17                      // 數據轉換
18                      data = System.Text.Encoding.UTF8.GetBytes(reply);
19                      // 發送數據到指定端點
20                      socketServer.SendTo(data, Remote);
21                 }
22             }
23              finally
24             {
25                  // 關閉套接字
26                  socketServer.Close();
27             }

 好,,這樣我們UDP的服務器端也搭建完成了,,接下來同理,搭建客戶端。。

實現原理和服務器端一樣,所以就不解釋了,直接上代碼吧:

UDP客戶端
 1             // 第一步 建立一個Socket
 2              Socket socketClient =  new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
 3 
 4              // 第二步 通過套接字收發報文
 5              Console.WriteLine( " 按任意鍵 開始向服務器發送數據 ");
 6             Console.ReadKey();
 7 
 8              byte[] data =  new  byte[ 1024 *  1024];
 9              string input, stringData;
10 
11             IPEndPoint endPoint =  new IPEndPoint(IPAddress.Parse( " 127.0.0.1 "),  8888);
12             data = Encoding.UTF8.GetBytes( " Hello Server,My Name Is HolyKnight_UdpClient ");
13 
14              // 將數據發送到服務器的終結點
15              socketClient.SendTo(data, endPoint);
16 
17              // 定義一個發送終結點,沒有具體的IP和Port
18              IPEndPoint sender =  new IPEndPoint(IPAddress.Any,  0);
19 
20              // 定義一個網絡地址
21              EndPoint Remote = (EndPoint)sender;
22 
23              // 重新實例化一個字節數組 用於存放接受到的數據
24              data =  new  byte[ 1024 *  1024];
25              // 接受數據 將數據保存到data數據 將遠程主機的節點保存到Remote終端中【注意ref引用】
26               int receive = socketClient.ReceiveFrom(data, ref Remote);
27 
28             Console.WriteLine( " Message Receive From {0} ", Remote.ToString());
29             Console.WriteLine(Encoding.UTF8.GetString(data,  0, receive));
30 
31              // 循環收發數據
32               while ( true)
33             {
34                  // 從鍵盤讀取數據
35                  input = Console.ReadLine();
36                  if (input ==  " exit ")
37                 {
38                      break;
39                 }
40                  // 同樣的發送數據到Remote節點
41                  socketClient.SendTo(Encoding.UTF8.GetBytes(input),Remote);
42                 data =  new  byte[ 1024 *  1024];
43 
44                  // 同樣的接受數據 並再次更新存儲終結點
45                  receive = socketClient.ReceiveFrom(data, ref Remote);
46                 stringData = Encoding.UTF8.GetString(data,  0, receive);
47 
48                 Console.WriteLine( " 服務器說: " + stringData);
49             }
50 
51              // 關閉套接字
52              Console.WriteLine( " Stopping Client ");
53             socketClient.Close();
54             Console.ReadKey();
55         }


好了,,這樣服務器端和客戶端都搭建完畢,接下來就是看看運行效果了,直接上圖

首先開啟服務器端:

我們看到【UDP Server Is Ok】和IP,Port,證明此時UDP服務器端已成功開啟了,,,

接下來開啟客戶端:


客戶端開啟成功,提示按任意鍵開始發送數據。。

接下來我們在客戶端連續給服務器發送三條消息

客戶端:

服務器端:


接下來我們在客戶端輸入“exit”請求停止通信,效果:

 輸入"exit“ 之后,客戶端就提示 "Stopping Client”,這樣就停止通信了,,,

 

哈哈,,就這樣,通過TCP和UDP實現通信聊天程序就完成了,,當然這個是最基礎的通信例子,,在下一篇博客中將用窗體程序和多線程來實現聊天程序,盡請關注,,,,

 

這里附上小Demo的源代碼:

/Files/holyknight-zld/SocketDemo/SocketDemo.rar

 

 

 

 

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM