HOWTO · Csharp
在 C# 中建立一個 UDP 伺服器
在本文中,我們將學習如何在 C# 中建立 UDP 伺服器。
本文將展示如何在 C# 中建立一個簡單的 UDP 伺服器。
在 C# 中建立一個 UDP 伺服器
簡單介紹一下背景,UDP 協議不需要與客戶端建立連線。資料只是傳輸而不驗證客戶端是否接收到它。
這種型別的協議通常用於廣播資料。由於 UDP 是無連線的,因此偵聽器無需線上即可接收訊息。
要使用 UDP 傳輸資料包,你需要知道託管服務的網路裝置的網路地址和服務的 UDP 埠號。流行服務的埠號由 Internet 號碼分配機構 (IANA) 定義;埠號的範圍是 1,024 到 65,535,可以分配給不在 IANA 列表中的服務。
在基於 IP 的網路上,特殊的網路地址用於處理 UDP 廣播訊息。以下解釋以 Internet 的 IP 版本 4 地址族為例。
通過設定主機標識的所有位,可以將廣播定向到網路的指定部分。使用地址 192.168.1.255 向網路上所有 IP 地址以 192.168.1 開頭的主機廣播。
我們現在準備建立或建立一個套接字,設定我們的 UDP 協議,並立即開始通訊。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
這些將是用於設定伺服器的庫。這些庫支援與網路相關的所有基本功能,例如構建套接字、處理 IPV4 地址等等。
public class SimpleUdpSrvr {
public static void Main() {
int recv;
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
}
int recv 行建立一個整數型別的 recv 變數,其中包含客戶端收到的字串訊息的位元組數。
byte[] data = new byte[1024]; line 用於為每個包含 1024 個單元格的單元格建立一個名為 data 的位元組大小的陣列,也稱為陣列大小。該陣列是在堆中動態建立的。
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050); 行告訴它為套接字建立一個 ipep 變數。傳入的資訊告訴它應該使用什麼樣的套接字。
IPEndPoint 類表示具有 IP 地址和埠號的網路端點;客戶端需要此配置資訊來連線我們的服務。傳入的 IPAddress.Any 引數告訴伺服器可以使用任何 IP 地址連線到 9050 埠號; ipep 變數也是動態建立的。
Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
這一行建立了一個 newsock 變數,一個我們將通過它進行通訊的套接字。傳入的引數告訴我們要建立什麼樣的套接字。
AddressFamily.InterNetwork 告訴我們我們需要本地 IP 地址。SocketType.Dgram 引數指出資料應該以資料包而不是資料包的形式流動。
最後,ProtocolType.Udp 引數告訴我們將使用的套接字的協議型別。現在,我們的套接字已建立。
newsock.Bind(ipep);
Console.WriteLine("Waiting for a client...");
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(sender);
到目前為止,我們已經在網路中建立了一個端點,以及一個用於通訊的套接字,newsock.Bind(ipep); line 現在將幫助我們將端點繫結到套接字。
ipep 是一個變數,它包含關於我們端點的資訊,並在我們的 newsock 物件的 bind() 函式中傳遞。
Console.WriteLine("Waiting for a client...");
此行在螢幕上列印伺服器正在等待客戶端傳送任何訊息。我們需要為將嘗試與伺服器通訊的傳送方建立另一個端點。
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
這一行建立了另一個端點,變數稱為 sender。在它的 IPAddress.Any 中傳遞的引數告訴我們期待任何 IP 地址,而 0 意味著它是埠號的萬用字元,系統應該看到並找到任何合適的埠分配給我們。
EndPoint Remote = (EndPoint)(sender); 行用於查詢傳送者的 IP 地址並將其儲存在 remote 變數中。
recv = newsock.ReceiveFrom(data, ref Remote);
Console.WriteLine("Message received from {0}:", Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
我們在程式開始時建立的 recv 變數現在用於 recv = newsock.ReceiveFrom(data, ref Remote); 線。我們使用之前建立的套接字 newsock 的 Receive() 函式,並且當前接收我們當時在套接字中的所有資料。
傳遞 Receive() 函式的引數告訴在哪裡儲存資料以及應該儲存或預期誰的資料。data 引數是被傳遞的位元組大小陣列,資料將被寫入資料陣列。
ref Remote 引數告訴 IP 地址傳送了資料,該函式將返回從該套接字獲取的位元組數並將其儲存到 recv 變數中。
Console.WriteLine("Message received from {0}:", Remote.ToString());
此行在螢幕上寫入通過套接字傳送資料的客戶端的 IP 地址。傳遞的引數 Remote.ToString() 將十進位制數字轉換為 ASCII 字元,而 remote 變數是引用客戶端的第二個端點。
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
這一行將實際資料寫入螢幕。通過套接字傳送的資料為原始形式,應轉換為 ASCII 字元才能讀取。
Encoding.ASCII.GetString(data, 0, recv) 行從作為引數傳遞的 data 變數中獲取資料,recv 引數(包含客戶端傳送的位元組數)告訴從螢幕上的 data 變數中寫入這麼多位元組。
string welcome = "Welcome to my test server";
data = Encoding.ASCII.GetBytes(welcome);
newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
string welcome = "歡迎來到我的測試伺服器"; 行用歡迎來到我的測試伺服器文字初始化歡迎字串變數。
data = Encoding.ASCII.GetBytes(welcome); line 將 welcome 變數作為 Encoding.ASCII.GetBytes() 函式中的引數並將其轉換為原始形式,以便準備好通過另一端的套接字傳送。
newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
這一行通過我們之前建立的套接字 newsock 傳送資料並使用 Send() 函式。它需要的引數是:包含要傳送的原始資料形式的 data 變數,data.Length 引數告訴在套接字上寫入多少位元組,因為資料的長度等於位元組數, SocketFlags.None 引數告訴我們將所有標誌保持為零,標誌是指示符,每個標誌都有其含義。
Remote 變數引數告訴我們要將資料傳送到的客戶端,因為 Remote 變數儲存客戶端的 IP 地址和埠號。
while (true) {
data = new byte[1024];
recv = newsock.ReceiveFrom(data, ref Remote);
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
newsock.SendTo(data, recv, SocketFlags.None, Remote);
}
while(true) 行表明它是一個無限迴圈,並且它的所有語句都將無限執行。資料 = 新位元組 [1024]; 行在執行時建立一個長度為 1024 的新位元組大小陣列。
recv = newsock.ReceiveFrom(data, ref Remote); line 從客戶端接收資料並將其儲存到資料陣列中。
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv)); 將資料寫入螢幕。
newsock.SendTo(data, recv, SocketFlags.None, Remote); 行將伺服器從它收到的相同資料傳送回客戶端。
之後,伺服器將再次停止並等待客戶端,客戶端傳送給伺服器的任何內容都會以相同的訊息進行響應。該伺服器將永遠不會終止,除非它崩潰或使用者手動停止它。
現在,當我們學習瞭如何在 C# 中建立 UDP 伺服器及其基本功能後,我們可以新增更多功能並根據我們的要求製作伺服器。
完整的原始碼:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class SimpleUdpSrvr {
public static void Main() {
int recv;
byte[] data = new byte[1024];
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 9050);
Socket newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
newsock.Bind(ipep);
Console.WriteLine("Waiting for a client...");
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)(sender);
recv = newsock.ReceiveFrom(data, ref Remote);
Console.WriteLine("Message received from {0}:", Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
string welcome = "Welcome to my test server";
data = Encoding.ASCII.GetBytes(welcome);
newsock.SendTo(data, data.Length, SocketFlags.None, Remote);
while (true) {
data = new byte[1024];
recv = newsock.ReceiveFrom(data, ref Remote);
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
newsock.SendTo(data, recv, SocketFlags.None, Remote);
}
}
}