| 
                           
                            | 
								
										
                                    | 编辑推荐: |  
										
                                    | 本文主要采用socket实现UDP、采用UDPClient类实现两个示例来介绍C#的UDP协议的同步实现。本文来自于知乎,由火龙果Anna编辑推荐
 |  |  一、摘要 总结基于C#的UDP协议的同步通信。 二、实验平台 Visual Studio 2010 三、实验原理 UDP传输协议同TCP传输协议的区别可查阅相关文档,此处不再赘述。 四、实例 4.1 采用socket实现UDP 由于UDP是一种无连接的协议。因此,为了使服务器应用能够发送和接收UDP数据包,则需要做两件事情: (1) 创建一个Socket对象; (2) 将创建的套接字对象与本地IPEndPoint进行绑定。 完成上述步骤后,那么创建的套接字就能够在IPEndPoint上接收流入的UDP数据包,或者将流出的UDP数据包发送到网络中其他任意设备。使用UDP进行通信时,不需要连接。因为异地的主机之间没有建立连接,所以UDP不能使用标准的Send()和Receive()t套接字方法,而是使用两个其他的方法:SendTo()和ReceiveFrom()。 SendTo()方法指定要发送的数据,和目标机器的IPEndPoint。该方法有多种不同的使用方法,可以根据具体的应用进行选择,但是至少要指定数据包和目标机器。如下: SendTo(byte[] data,EndPoint Remote) ReceiveFrom()方法同SendTo()方法类似,但是使用EndPoint对象声明的方式不一样。利用ref修饰,传递的不是一个EndPoint对象,而是将参数传递给一个EndPoint对象。 UDP应用不是严格意义上的真正的服务器和客户机,而是平等的关系,即没有主与次的关系。为了简便起见,仍然把下面的这个应用叫做UDP服务器。 服务器端代码: 
                             
                              | using System; using System.Collections.Generic;
 using System.Text;
 using System.Net;
 using System.Net.Sockets;
 namespace UDP
 {
 class Program
 {
 static void Main(string[] args)
 {
 int recv;
 byte[] data = new byte[1024];
 //得到本机IP,设置TCP端口号
 IPEndPoint ip =  new IPEndPoint(IPAddress.Any, 
                                  8001);
 Socket newsock =  new Socket(AddressFamily.InterNetwork, 
                                  SocketType.Dgram,  ProtocolType.Udp);
 //绑定网络地址
 newsock.Bind(ip);
 Console.WriteLine ("This is a Server, 
                                  host name is {0}",  Dns.GetHostName());
 //等待客户机连接
 Console.WriteLine("Waiting for a client");
 //得到客户机IP
 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 = "你好 ! ";
 //字符串与字节数组相互转换
 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);
 }
 }
 }
 }
 |  对于接收流入的UDP服务器程序来说,必须将程序与本地系统中指定的UDP端口进行绑定。这就可以通过使用合适的本地IP地址创建一个IPEndPoint对象,以及合适的UDP端口号。上述范例程序中的UDP服务器能够在端口8001从网络上接收任意流入的UDP数据包。 UDP客户机程序与服务器程序非常类似。 因为客户机不需要在指定的UDP端口等待流入的数据,因此,不使用Bind()方法,而是使用在数据发送时系统随机指定的一个UDP端口,而且使用同一个端口接收返回的消息。在开发产品时,要为客户机指定一套UDP端口,以便服务器和客户机程序使用相同的端口号。UDP客户机程序首先定义一个IPEndPoint,UDP服务器将发送数据包到这个IPEndPoint。如果在远程设备上运行UDP服务器程序,在IPEndPoint定义中必须输入适当的IP地址和UDP端口号信息。 客户端代码: 
                             
                              | using System; using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Net;
 using System.Net.Sockets;
 namespace UDPClient
 {
 class Program
 {
 static void Main(string[] args)
 {
 byte[] data = new byte[1024];
 string input, stringData;
 //构建TCP 服务器
 Console.WriteLine("This is a Client, host 
                                  name is {0}", Dns.GetHostName());
 //设置服务IP,设置TCP端口号
 IPEndPoint ip = new IPEndPoint (IPAddress.Parse("127.0.0.1"), 
                                  8001);
 //定义网络类型,数据连接类型和网络协议UDP
 Socket server = new Socket (AddressFamily.InterNetwork, 
                                  SocketType.Dgram, ProtocolType.Udp);
 string welcome = "你好! ";
 data = Encoding.ASCII.GetBytes(welcome);
 server.SendTo(data, data.Length, SocketFlags.None, 
                                  ip);
 IPEndPoint sender = new IPEndPoint(IPAddress.Any, 
                                  0);
 EndPoint Remote = (EndPoint)sender;
 data = new byte[1024];
 //对于不存在的IP地址,加入此行代码后,可以在指定时间内解除阻塞模式限制
 int recv = server.ReceiveFrom( data, ref Remote);
 Console.WriteLine("Message received from 
                                   {0}: ", Remote.ToString());
 Console.WriteLine (Encoding.ASCII.GetString 
                                  (data, 0, recv));
 while (true)
 {
 input = Console.ReadLine();
 if (input == "exit")
 break;
 server.SendTo (Encoding.ASCII.GetBytes(input), 
                                  Remote);
 data = new byte[1024];
 recv = server.ReceiveFrom (data, ref Remote);
 stringData =  Encoding.ASCII.GetString (data, 
                                  0, recv);
 Console.WriteLine(stringData);
 }
 Console.WriteLine ("Stopping Client.");
 server.Close();
 }
 }
 }
 |  上述代码的实现逻辑为:相关设置完成后,服务器端先向客户端发送信息,之后客户端通过键盘发送字符串,服务器端收到后再发送给客户端,如此循环。 4.2 采用UDPClient类实现 服务器端代码: 
                             
                              | using System; using System.Net;
 using System.Net.Sockets;
 using System.Text;
 public class Custom
 {
 // 设置IP,IPV6
 private static readonly IPAddress GroupAddress 
                                  = IPAddress.Parse("IP地址");
 // 设置端口
 private const int GroupPort = 11000;
 private static void StartListener()
 {
 bool done = false;
 UdpClient listener = new UdpClient();
 IPEndPoint groupEP = new IPEndPoint(GroupAddress, 
                                  GroupPort);
 try
 {
 //IPV6,组播
 listener.JoinMulticastGroup(GroupAddress);
 listener.Connect(groupEP);
 while (!done)
 {
 Console.WriteLine("Waiting for broadcast");
 byte[] bytes = listener.Receive(ref groupEP);
 Console.WriteLine("Received broadcast 
                                  from {0} :\n {1}\n", groupEP.ToString(), 
                                  Encoding.ASCII.GetString(bytes, 0, bytes.Length));
 }
 listener.Close();
 }
 catch (Exception e)
 {
 Console.WriteLine(e.ToString());
 }
 }
 public static int Main(String[] args)
 {
 StartListener();
 return 0;
 }
 }
 |  客户端代码: 
                             
                              | using System; using System.Net;
 using System.Net.Sockets;
 using System.Text;
 public class Client
 {
 private static IPAddress GroupAddress = IPAddress.Parse("IP地址");
 private static int GroupPort = 11000;
 private static void Send(String message)
 {
 UdpClient sender = new UdpClient();
 IPEndPoint groupEP = new IPEndPoint(GroupAddress, 
                                  GroupPort);
 try
 {
 Console.WriteLine("Sending datagram : {0}", 
                                  message);
 byte[] bytes = Encoding.ASCII.GetBytes(message);
 sender.Send(bytes, bytes.Length, groupEP);
 sender.Close();
 }
 catch (Exception e)
 {
 Console.WriteLine(e.ToString());
 }
 }
 public static int Main(String[] args)
 {
 Send(args[0]);
 return 0;
 }
 }
 |  以上代码需要说明的是: (1) 上述代码是基于IPV6地址的组播模式。IPv4中的广播(broadcast)可以导致网络性能的下降甚至广播风暴(broadcast 
                            storm)。在IPv6中就不存在广播这一概念了,取而代之的是组播(multicast)和任意播(anycast)。 (2) IPV6地址表示方法: a) X:X:X:X:X:X:X:X(每个X代表16位的16进制数字),不区分大小写; b) 排头的0可省略,比如09C0就可以写成9C0,0000可以写成0; c) 连续为0的字段可以以::来代替,但是整个地址中::只能出现一次,比如FF01:0:0:0:0:0:0:1就可以简写成FF01::1。 (3) 如果是采用窗体的形式建议使用多线程,如下这种格式,否则在接收数据时可能会出现死机的现象。 
                             
                              | // 创建一个子线程 Thread thread = new Thread(
 delegate()
 {
 try
 {
 //在这里写你的代码
 }
 catch (Exception )
 {
 }
 }
 );
 thread.Start();
 |    |