c#如何使用UDP進(jìn)行聊天通信
c#使用UDP進(jìn)行聊天通信
UDP和TCP都是網(wǎng)絡(luò)通信中不可缺少的部分,兩者在不同的環(huán)境中,應(yīng)用的場景不一樣,UDP在網(wǎng)絡(luò)不好的情況下,傳輸會丟包,也就是會丟數(shù)據(jù),而TCP不會這樣,所以重要的數(shù)據(jù)使用TCP傳輸,但是TCP對網(wǎng)絡(luò)的資源消耗非常的大,例如視頻,音頻等大量的數(shù)據(jù),這個(gè)時(shí)候就選擇UDP,因?yàn)閁DP占用網(wǎng)絡(luò)資源比較低,就算丟一幀二幀的圖像的數(shù)據(jù),也不會有影響的。
UDP只管發(fā)送,不管你有沒有接收到信息,比較主動(dòng),同理,也會一直接收,只要在線,就能接受對方的信息。UDP比TCP的使用更加的簡單。
UDP通信可以分為使用UDP和UdpClient。UdpClient是Socket的一種封裝。其實(shí)UDP通信沒有絕對的服務(wù)端和客戶端分別,因?yàn)槎际沁B接上,就可以發(fā)送和接收。
使用UDP方式,需要注意發(fā)送消息的IP地址和端口與接收消息的IP地址和端口。
服務(wù)端代碼
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp1 { class Program { static void Main(string[] args) { //udp 服務(wù)端 Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); server.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6001));//綁定端口號和IP Console.WriteLine("服務(wù)端已經(jīng)開啟"); Thread t = new Thread(()=>ReciveMsg(server));//開啟接收消息線程 t.Start(); Thread t2 = new Thread(()=>sendMsg(server));//開啟發(fā)送消息線程 t2.Start(); } static void sendMsg(Socket server) { EndPoint point = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6000); //向指定的IP和端口發(fā)送消息 while (true) { string msg = Console.ReadLine(); server.SendTo(Encoding.UTF8.GetBytes(msg), point); } } static void ReciveMsg(Socket server) { while (true) { //EndPoint point = new IPEndPoint(IPAddress.Any, 0); //向所有的IP和端口接收消息 EndPoint point = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6000); //向指定的IP和端口接收消息 byte[] buffer = new byte[1024]; int length = server.ReceiveFrom(buffer, ref point);//接收數(shù)據(jù)報(bào) string message = Encoding.UTF8.GetString(buffer, 0, length); Console.WriteLine("收到了消息:" + message); } } } }
客戶端代碼
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp2 { class Program { static void Main(string[] args) { Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); client.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6000)); Thread t = new Thread(() => sendMsg(client)); t.Start(); Thread t2 = new Thread(() => ReciveMsg(client)); t2.Start(); Console.WriteLine("客戶端已經(jīng)開啟"); } static void sendMsg(Socket client) { EndPoint point = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6001); //向指定的IP和端口發(fā)送消息 while (true) { string msg = Console.ReadLine(); client.SendTo(Encoding.UTF8.GetBytes(msg), point); } } static void ReciveMsg(Socket client) { while (true) { //EndPoint point = new IPEndPoint(IPAddress.Any, 0); //向所有的IP和端口接收消息 EndPoint point = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 6001); //向指定的IP和端口接收消息 byte[] buffer = new byte[1024]; int length = client.ReceiveFrom(buffer, ref point);//接收數(shù)據(jù)報(bào) string message = Encoding.UTF8.GetString(buffer, 0, length); Console.WriteLine("收到了消息:" + message); } } } }
效果預(yù)覽
使用UdpClient方式,需要注意發(fā)送消息的IP地址和端口與接收消息的IP地址和端口
服務(wù)端代碼
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp1 { class Program { static void Main(string[] args) { //創(chuàng)建udpclient 綁定ip跟端口號 UdpClient udpClient = new UdpClient(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8090)); Console.WriteLine("UdpClient服務(wù)端已經(jīng)開啟"); Thread t = new Thread(() => ReciveMsg(udpClient));//開啟接收消息線程 t.Start(); Thread t2 = new Thread(() => sendMsg(udpClient));//開啟發(fā)送消息線程 t2.Start(); } static void sendMsg(UdpClient udpClient) { while (true) { string message = Console.ReadLine(); byte[] data = Encoding.UTF8.GetBytes(message); udpClient.Send(data, data.Length, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8091)); //發(fā)送到指定的IP地址和端口信息 } } static void ReciveMsg(UdpClient udpClient) { while (true) { //接收數(shù)據(jù) //IPEndPoint point = new IPEndPoint(IPAddress.Any, 0); //接收所有的IP地址和端口信息 IPEndPoint point = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8091); //接收指定的IP地址和端口信息 byte[] data = udpClient.Receive(ref point);// string message = Encoding.UTF8.GetString(data); Console.WriteLine("收到了消息:" + message); } } } }
客戶端代碼
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace ConsoleApp2 { class Program { static void Main(string[] args) { //創(chuàng)建udpclient對象 UdpClient client = new UdpClient(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8091)); Console.WriteLine("UdpClient客戶端已經(jīng)開啟"); Thread t = new Thread(() => sendMsg(client)); t.Start(); Thread t2 = new Thread(() => ReciveMsg(client)); t2.Start(); } static void sendMsg(UdpClient client) { while (true) { string message = Console.ReadLine(); byte[] data = Encoding.UTF8.GetBytes(message); client.Send(data, data.Length, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8090)); } } static void ReciveMsg(UdpClient udpClient) { while (true) { //接收數(shù)據(jù) //IPEndPoint point = new IPEndPoint(IPAddress.Any, 0); //接收所有的IP地址和端口信息 IPEndPoint point = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8090); //接收指定的IP地址和端口信息 byte[] data = udpClient.Receive(ref point); string message = Encoding.UTF8.GetString(data); Console.WriteLine("收到了消息:" + message); } } } }
效果預(yù)覽
從以上的案例來看,UDP和UdpClient的區(qū)別基本上都是一樣的,一個(gè)使用了Socket 類,一個(gè)使用了UdpClient類,然后都是綁定對應(yīng)的IP地址和端口,然后就是分別調(diào)用Socket類的方法,進(jìn)行發(fā)送消息和接收消息,調(diào)用UdpClient類的方法,進(jìn)行發(fā)送消息和接收信息。
其實(shí)在新建類的時(shí)候,可以不用先進(jìn)行連接,可以把IP地址和端口,以及消息一次性發(fā)出去。
拓展
單播,廣播,多播三者的區(qū)別
單播
用于兩個(gè)主機(jī)之間的端對端通信,指定了固定的IP地址和端口,就是一對一的對話,其他人聽不到你們說的話,類似私聊。
代碼:就是上面的代碼,指定了固定的IP地址和端口號,發(fā)送和接收都互相對應(yīng)。
廣播
用于一個(gè)主機(jī)對整個(gè)局域網(wǎng)上所有主機(jī)上的數(shù)據(jù)通信,就是一個(gè)人大聲說話,所有的人都能聽到,類似群聊。
代碼:修改成下面2句即可,發(fā)送端和接收端都要修改。
UDP服務(wù)端
server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, true); //Broadcast開啟廣播 EndPoint point = new IPEndPoint(IPAddress.Broadcast, 4567); //開啟廣播,端口是4567
UDP客戶端
EndPoint iep = new IPEndPoint(IPAddress.Any, 4567); //任意ip,端口就是服務(wù)端的4567 EndPoint point = new IPEndPoint(IPAddress.Any, 4567); //廣播,端口是4567
UdpClient服務(wù)端
UdpClient udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, 0)); IPEndPoint point = new IPEndPoint(IPAddress.Broadcast, 4567); //開啟廣播,端口是4567
UdpClient客戶端
UdpClient client = new UdpClient(new IPEndPoint(IPAddress.Any, 4567)); IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 0);
多播
介于單播和廣播之間,也叫組播,從名字上面就能知道,建立一個(gè)組,然后向組內(nèi)的人員發(fā)送消息,就類似,微信臨時(shí)拉一個(gè)群,指定群內(nèi)的人,向群內(nèi)通知信息。
代碼:修改成下面2句即可,發(fā)送端和接收端都要修改。
加入多播
udpClient.JoinMulticastGroup(IPAddress.Parse("224.0.0.0"));//將 UdpClient 添加到多播組;IPAddress.Parse將IP地址字符串轉(zhuǎn)換為IPAddress 實(shí)例 IPEndPoint multicast = new IPEndPoint(IPAddress.Parse("224.0.0.0"), 7788); //將網(wǎng)絡(luò)終結(jié)點(diǎn)表示為 IP 地址和端口號 7788是目的端口
退出多播
udpClient.DropMulticastGroup(IPAddress.Parse("224.0.0.0"));//將 UdpClient 從多播組中移除;IPAddress.Parse將IP地址字符串轉(zhuǎn)換為IPAddress 實(shí)例 IPEndPoint multicast = new IPEndPoint(IPAddress.Parse("224.0.0.0"), 7788); //將網(wǎng)絡(luò)終結(jié)點(diǎn)表示為 IP 地址和端口號 7788是目的端口
帶界面操作
代碼
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); CheckForIllegalCrossThreadCalls = false;//在其他線程中可以調(diào)用主窗體控件 } UdpClient udpClient; UdpClient client; private void Form1_Load(object sender, EventArgs e) { Thread js = new Thread(() => { client = new UdpClient(new IPEndPoint(IPAddress.Any, 4567)); IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Any, 0); while (true) { try { if (client.Available <= 0) continue; if (client.Client == null) return; byte[] bytes = client.Receive(ref iPEndPoint); string str = Encoding.Default.GetString(bytes); //Invoke(new Action(() => textBox2.Text = str)); textBox2.Text = str; } catch (Exception) { throw; } Thread.Sleep(1000); } }); js.Start(); } private void button1_Click(object sender, EventArgs e) { udpClient = new UdpClient(new IPEndPoint(IPAddress.Any, 0)); IPEndPoint point = new IPEndPoint(IPAddress.Broadcast, 4567); //開啟廣播,端口是4567 if (textBox1.Text != null) { Byte[] sendBytes = Encoding.Default.GetBytes(textBox1.Text); udpClient.Send(sendBytes, sendBytes.Length, point); } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { udpClient.Dispose(); udpClient.Close(); client.Dispose(); client.Close(); } } }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
淺析JAVA中過濾器、監(jiān)聽器、攔截器的區(qū)別
本文通過代碼分析和文字說明的方式給大家淺析JAVA中過濾器、監(jiān)聽器、攔截器的區(qū)別,感興趣的朋友一起看下吧2015-09-09C#搜索TreeView子節(jié)點(diǎn),保留父節(jié)點(diǎn)的方法
這篇文章主要介紹了C#搜索TreeView子節(jié)點(diǎn),保留父節(jié)點(diǎn)的方法,實(shí)例分析了C#操作TreeView節(jié)點(diǎn)的相關(guān)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-09-09c#使用linq技術(shù)創(chuàng)建xml文件的小例子
c#使用linq技術(shù)創(chuàng)建xml文件的小例子,需要的朋友可以參考一下2013-03-03C#實(shí)現(xiàn)驗(yàn)證身份證是否合法的方法
這篇文章主要介紹了C#實(shí)現(xiàn)驗(yàn)證身份證是否合法的方法,實(shí)例分析了通過自定義函數(shù)實(shí)現(xiàn)針對身份證合法性驗(yàn)證的技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2015-03-03詳解C#如何計(jì)算一個(gè)實(shí)例占用多少內(nèi)存
我們都知道CPU和內(nèi)存是程序最為重要的兩類指標(biāo),那么有多少人真正想過一個(gè)類型的實(shí)例在內(nèi)存中究竟占多少字節(jié),本文就來用C#計(jì)算一下一個(gè)實(shí)例占用多少內(nèi)存吧2023-06-06直接在線預(yù)覽Word、Excel、TXT文件之ASP.NET
這篇文章主要用asp.net技術(shù)實(shí)現(xiàn)直接在線預(yù)覽word、excel、txt文件,有需要的朋友可以參考下2015-08-08