首頁  >  文章  >  後端開發  >  詳解基於C#的UDP協定的同步通訊的範例程式碼

詳解基於C#的UDP協定的同步通訊的範例程式碼

黄舟
黄舟原創
2017-03-23 11:38:101949瀏覽

本篇文章主要介紹了基於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