UDP信息接收與發送

轉載:http://www.cnblogs.com/sunev/archive/2012/08/08/2627247.html

1、摘要

   總結基於C#的UDP協議的同步通訊。html

 

2、實驗平臺

   Visual Studio 2010數組

 

3、實驗原理

   UDP傳輸協議同TCP傳輸協議的區別可查閱相關文檔,此處再也不贅述。服務器

 

4、實例

 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對象。
socket

 

  UDP應用不是嚴格意義上的真正的服務器和客戶機,而是平等的關係,即沒有主與次的關係。爲了簡便起見,仍然把下面的這個應用叫作UDP服務器。性能

  服務器端代碼:spa

複製代碼
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端口號信息。
code

  客戶端代碼:orm

複製代碼
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();
相關文章
相關標籤/搜索