首页 后端开发 C#.Net教程 详解基于C#的UDP协议的同步通信的示例代码

详解基于C#的UDP协议的同步通信的示例代码

Mar 23, 2017 am 11:38 AM

本篇文章主要介绍了基于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();
登录后复制

以上是详解基于C#的UDP协议的同步通信的示例代码的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

使用 C# 的活动目录 使用 C# 的活动目录 Sep 03, 2024 pm 03:33 PM

使用 C# 的 Active Directory 指南。在这里,我们讨论 Active Directory 在 C# 中的介绍和工作原理以及语法和示例。

C# 序列化 C# 序列化 Sep 03, 2024 pm 03:30 PM

C# 序列化指南。这里我们分别讨论C#序列化对象的介绍、步骤、工作原理和示例。

C# 中的随机数生成器 C# 中的随机数生成器 Sep 03, 2024 pm 03:34 PM

C# 随机数生成器指南。在这里,我们讨论随机数生成器的工作原理、伪随机数和安全数的概念。

C# 数据网格视图 C# 数据网格视图 Sep 03, 2024 pm 03:32 PM

C# 数据网格视图指南。在这里,我们讨论如何从 SQL 数据库或 Excel 文件加载和导出数据网格视图的示例。

C# 中的模式 C# 中的模式 Sep 03, 2024 pm 03:33 PM

C# 模式指南。在这里,我们讨论 C# 中模式的介绍和前 3 种类型,以及其示例和代码实现。

C# 中的质数 C# 中的质数 Sep 03, 2024 pm 03:35 PM

C# 素数指南。这里我们讨论c#中素数的介绍和示例以及代码实现。

C# 中的阶乘 C# 中的阶乘 Sep 03, 2024 pm 03:34 PM

C# 阶乘指南。这里我们讨论 C# 中阶乘的介绍以及不同的示例和代码实现。

c#多线程和异步的区别 c#多线程和异步的区别 Apr 03, 2025 pm 02:57 PM

多线程和异步的区别在于,多线程同时执行多个线程,而异步在不阻塞当前线程的情况下执行操作。多线程用于计算密集型任务,而异步用于用户交互操作。多线程的优势是提高计算性能,异步的优势是不阻塞 UI 线程。选择多线程还是异步取决于任务性质:计算密集型任务使用多线程,与外部资源交互且需要保持 UI 响应的任务使用异步。

See all articles