總結了基於C#的UDP協議的同步通信。
二、實驗平臺
Visual Studio 2010
三、實驗原理
UDP傳輸協議和TCP傳輸協議的區別可以在相關文檔中找到,這裏不再贅述。
第四,例子
4.1使用socket實現UDP。
因為UDP是壹種無連接協議。因此,為了使服務器應用程序能夠發送和接收UDP數據包,需要做兩件事:
(1)創建套接字對象;
(2)將創建的socket對象與本地IPEndPoint綁定。
完成上述步驟後,創建的套接字可以在IPEndPoint上接收傳入的UDP數據包,或者向網絡中的任何其他設備發送傳出的UDP數據包。使用UDP通信時,不需要連接。由於異地主機之間沒有連接,UDP無法使用標準的Send()和Receive()t socket方法,而是使用另外兩種方法:SendTo()和ReceiveFrom()。
SendTo()方法指定要發送的數據和目標機器的IPEndPoint。該方法有多種不同的使用方式,可以根據具體應用進行選擇,但至少要指定數據包和目標機器。如下所示:
SendTo(byte[]數據,端點遠程)
ReceiveFrom()方法類似於SendTo()方法,但它是使用EndPoint對象以不同的方式聲明的。使用ref修飾,不是傳遞端點對象,而是將參數傳遞給端點對象。
UDP應用不是嚴格意義上的真正的服務器和客戶端,而是壹種平等的關系,即沒有主次關系。為了簡單起見,下面的應用程序仍然稱為UDP服務器。
服務器端代碼:
復制代碼
使用系統;
使用系統。集合。泛型;
使用系統。文本;
使用System.Net;
使用系統。Net . Sockets
命名空間UDP
{
班級計劃
{
靜態void Main(string[] args)
{
int recv
byte[] data =新字節[1024];
//獲取本地IP,設置TCP端口號。
IPEndPoint IP = new IPEndPoint(IP address。Any,8001);
Socket newsock =新套接字(AddressFamily。互聯網,SocketType。協議類型。UDP);
//綁定網絡地址
紐索克。綁定(IP);
控制臺。WriteLine("這是壹個服務器,主機名是{0} ",Dns。get hostname());
//等待客戶端連接
控制臺。WriteLine(“等待客戶”);
//獲取客戶端IP
IPEndPoint sender = new IPEndPoint(IP address。Any,0);
EndPoint Remote = (EndPoint)(發送方);
recv = newsock。ReceiveFrom(data,ref Remote);
控制臺。WriteLine("從{0}接收的消息:"),遠程。ToString());
控制臺。WriteLine(編碼。ASCII.GetString(data,0,recv));
//客戶端連接成功後,發送信息。
String welcome = "妳好!";
//字符串和字節數組相互轉換
數據=編碼。ASCII.GetBytes(歡迎);
//發送信息
紐索克。SendTo(數據,數據。長度,SocketFlags。無,遠程);
while(真)
{
數據=新字節[1024];
//發送和接收信息
recv = newsock。ReceiveFrom(data,ref Remote);
控制臺。WriteLine(編碼。ASCII.GetString(data,0,recv));
紐索克。SendTo(data,recv,SocketFlags。無,遠程);
}
}
}
}
復制代碼
對於傳入的UDP服務器程序,該程序必須綁定到本地系統中指定的UDP端口。這允許您通過使用適當的本地IP地址和適當的UDP端口號來創建IPEndPoint對象。上述示例程序中的UDP服務器可以在端口8001接收任何來自網絡的UDP數據包。
UDP客戶端程序與服務器程序非常相似。
因為客戶端不需要在指定的UDP端口等待傳入的數據,所以不使用Bind()方法,而是在發送數據時使用系統隨機指定的壹個UDP端口,並使用同壹個端口接收返回的消息。開發產品時,應該為客戶端指定壹組UDP端口,以便服務器和客戶端程序可以使用相同的端口號。UDP客戶端程序首先定義UDP服務器將向其發送數據包的IPEndPoint。如果在遠程設備上運行UDP服務器程序,則必須在IPEndPoint的定義中輸入適當的IP地址和UDP端口號信息。
客戶代碼:
復制代碼
使用系統;
使用系統。集合。泛型;
使用系統。Linq
使用系統。文本;
使用System.Net;
使用系統。Net . Sockets
命名空間UDPClient
{
班級計劃
{
靜態void Main(string[] args)
{
byte[] data =新字節[1024];
字符串輸入,stringData
//構建壹個TCP服務器
控制臺。WriteLine("這是壹個客戶端,主機名是{0} ",Dns。get hostname());
//設置服務IP和TCP端口號。
IPEndPoint IP = new IPEndPoint(IP address。Parse("127.0.0.1 "),8001);
//定義網絡類型、數據連接類型和網絡協議UDP。
套接字服務器=新套接字(AddressFamily。互聯網,SocketType。協議類型。UDP);
String welcome = "妳好!";
數據=編碼。ASCII.GetBytes(歡迎);
服務器。SendTo(數據,數據。長度,SocketFlags。無,IP);
IPEndPoint sender = new IPEndPoint(IP address。Any,0);
EndPoint Remote = (EndPoint)發送方;
數據=新字節[1024];
//對於不存在的IP地址,添加這行代碼後,可以在指定時間內解除阻塞模式限制。
int recv =服務器。ReceiveFrom(data,ref Remote);
控制臺。WriteLine("從{0}接收的消息:"),遠程。ToString());
控制臺。WriteLine(編碼。ASCII.GetString(data,0,recv));
while(真)
{
輸入=控制臺。ReadLine();
if (input == "exit ")
打破;
服務器。SendTo(編碼。ASCII.GetBytes(輸入),遠程);
數據=新字節[1024];
recv =服務器。ReceiveFrom(data,ref Remote);
stringData =編碼。ASCII.GetString(data,0,recv);
控制臺。WriteLine(string data);
}
控制臺。WriteLine("停止客戶端。");
服務器。close();
}
}
}
復制代碼
上面代碼的實現邏輯是:相關設置完成後,服務器先向客戶端發送信息,然後客戶端通過鍵盤發送字符串,服務器接收後再發送給客戶端,以此類推。
4.2由UDPClient類實現。
服務器端代碼:
復制代碼
使用系統;
使用System.Net;
使用系統。Net . Sockets
使用系統。文本;
公共階級習俗
{
//設置IP,IPV6。
私有靜態只讀IP地址組地址= IP地址。parse ("IP地址");
//設置端口
private const int group port = 11000;
私有靜態void StartListener()
{
bool done = false
UDP client listener = new UDP client();
IPEndPoint group EP = new IPEndPoint(group address,group port);
嘗試
{
//IPV6,多播
聽眾。JoinMulticastGroup(group address);
聽眾。連接(groupEP);
而(!完成)
{
控制臺。WriteLine(“等待廣播”);
byte[] bytes =偵聽器。接收(ref group EP);
控制臺。WriteLine("已接收來自{0}的廣播:\n {1}\n ",groupEP。ToString(),編碼。ASCII.GetString(字節,0,字節。長度));
}
聽眾。close();
}
捕捉(例外e)
{
控制臺。WriteLine(e . ToString());
}
}
public static int Main(String[]args)
{
start listener();
返回0;
}
}
復制代碼
客戶代碼:
復制代碼
使用系統;
使用System.Net;
使用系統。Net . Sockets
使用系統。文本;
公共類客戶端
{
私有靜態IP地址組地址= IP地址。parse ("IP地址");
私有靜態int group port = 11000;
私有靜態void發送(字符串消息)
{
UDP client sender = new UDP client();
IPEndPoint group EP = new IPEndPoint(group address,group port);
嘗試
{
控制臺。WriteLine("發送數據報:{0} ",message);
byte[] bytes =編碼。ASCII . GetBytes(message);
發件人。發送(字節,字節。長度,group EP);
發件人。close();
}
捕捉(例外e)
{
控制臺。WriteLine(e . ToString());
}
}
public static int Main(String[]args)
{
send(args[0]);
返回0;
}
}
復制代碼
上面的代碼需要解釋壹下:
(1)以上代碼是基於IPV6地址的組播模式。用IPv4廣播會導致網絡性能下降,甚至出現廣播風暴。在IPv6中,沒有廣播這樣的概念,只有組播和任播。
(2) IPV6地址表示方法:
a)x:x:x:x:x:x:x:x(每個x代表16的16位),不區分大小寫;
b)前導0可以省略,例如09C0可以寫成9C0,0000可以寫成0;
c)連續零的字段可以替換為::,但是::在整個地址中只能出現壹次。比如FF01: 0: 0: 0: 1可以縮寫為FF01: 1。
(3)如果是表單形式的,建議使用這種格式,否則接收數據時可能會崩潰。
復制代碼
//創建子線程
線程線程=新線程(
代理人()
{
嘗試
{
//在這裏寫代碼。
}
捕捉(異常)
{
}
}
);
線程。start();
復制代碼