好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

基于C#的UDP协议的同步通信实现代码

一、摘要

总结基于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();

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

dy("nrwz");

查看更多关于基于C#的UDP协议的同步通信实现代码的详细内容...

  阅读:39次