作成したクラスの概要
今回作成したのはSystem.Net.Sockets.Socketクラスを使用したUdpClientクラスとUdpReceiverクラスです。
C#にはSystem.Net.SocketsにはUdpClientクラスが既に用意されてますが、今回はSystem.Net.Sockets.Socketで自作しました。
関連ページ
UdpClientクラスのコード
実際のクライアント側コードはこちらです。
/// <summary>
/// UdpReceiverクラス
/// </summary>
internal class UdpReceiver
{
    private Socket socket;
    private IPEndPoint localEP;
    public byte[] receiveData;
    public byte[] sendData;
    public bool IsLitenOn;
    private Task comTask;
    //デリゲートの宣言
    //ReceiveEventArgs型のオブジェクトを返すようにする
    public delegate void ReceiveEventHandler(object sender, ReceiveEventArgs e);
    //イベントデリゲートの宣言
    public event ReceiveEventHandler Receive;
    /// <summary>
    /// コンストラクター
    /// 受信ポートを引数にしてインスタンスを作成
    /// </summary>
    /// <param name="port"></param>
    public UdpReceiver(int port)
    {
        localEP = new IPEndPoint(IPAddress.Any, port);
        IsLitenOn = true;
    }
    /// <summary>
    /// GenSocket
    /// サーバー用ソケットを作成する
    /// </summary>
    /// <returns></returns>
    public int GenSocket()
    {
        int code = 0;
        byte[] buf = new byte[1024];
        int record = 0;
        socket = new Socket(IPAddress.Any.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
        socket.Bind(localEP);
        //socket.Listen(10);
        while (IsLitenOn)
        {
            //Socket handler = socket.Accept();
            record = socket.Receive(buf);
            receiveData = new byte[record];
            Array.Copy(buf, receiveData, record);
            //Responseデータ作成
            ReceiveEventArgs e = new ReceiveEventArgs();
            e.Message = Encoding.UTF8.GetString(receiveData);
            Receive(this, e);
        }
        return code;
    }
    /// <summary>
    /// ComTaskGen
    /// 非同期タスクで"GenSocket()"メソッドを開始する
    /// </summary>
    public void ComTaskGen()
    {
        Func<int> func = GenSocket;
        comTask = new Task<int>(func);
        comTask.Start();
    }
}
UdpReceiverクラスのコード
UDPプロトコルはデータ送りっぱなしのプロトコルなので、Receiverとしています。
/// <summary>
/// UdpClientクラス
/// </summary>
internal class UdpClient
{
    public Socket socket;
    public IPAddress ipAddress;
    private IPEndPoint remoteEP;
    public byte[] receiveData;
    public byte[] sendData;
    public Task comTask;
    //デリゲートの宣言
    //ReceiveEventArgs型のオブジェクトを返すようにする
    public delegate string ReceiveEventHandler(object sender, ReceiveEventArgs e);
    //イベントデリゲートの宣言
    public event ReceiveEventHandler Receive;
    /// <summary>
    /// コンストラクター
    /// サーバホスト名、送信先ポートを引数にしてインスタンスを作成
    /// </summary>
    /// <param name="hostName"></param>
    /// <param name="port"></param>
    public UdpClient(string hostName, int port)
    {
        IPHostEntry ipHostList = Dns.GetHostEntry(hostName);
        for (int i = 0; i < ipHostList.AddressList.Length; i++)
        {
            if (ipHostList.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
            {
                ipAddress = ipHostList.AddressList[i];
                remoteEP = new IPEndPoint(ipAddress, port);
                break;
            }
        }
    }
    /// <summary>
    /// SetSendData
    /// 文字列データを送信用プロパティに格納する
    /// </summary>
    /// <param name="msg"></param>
    public void SetSendData(string msg)
    {
        sendData = Encoding.UTF8.GetBytes(msg);
    }
    /// <summary>
    /// GenSocket
    /// 送信用ソケットを作成しサーバにリクエストを送る
    /// </summary>
    /// <returns></returns>
    private int GenSocket()
    {
        int code = 0;
        socket = new Socket(ipAddress.AddressFamily, SocketType.Dgram, ProtocolType.Udp);
        socket.Connect(remoteEP);
        socket.Send(sendData);
        socket.Shutdown(SocketShutdown.Both);
        socket.Close();
        return code;
    }
    /// <summary>
    /// ComTaskGen
    /// 非同期タスクで送信用ソケット作成、実行する
    /// </summary>
    public void ComTaskGen()
    {
        Func<int> func = GenSocket;
        comTask = new Task<int>(func);
        comTask.Start();
    }
}
Receiveイベントの実装方法
UdpReceiverで実装されるReceiveイベントの実装方法です。
UI操作用delegateの定義(必要な場合のみ)
TcpServerクラス等と同様にReceiveイベントでUI処理を行う場合は後程使用するUI処理用delegateを定義しておきます。処理フローで説明した通り、通信はサブタスクで行うため、サブスレッドからUIの直接編集ができないことに注意してください。
private delegate void UiControlData(object obj);
UdpServer_Receiveイベントの定義と追加
まず、Receiveイベントを使用するには、イベント発生時に呼び出すメソッドの定義が必要です。
コード例ではUIに受信文字列を表示します。
private void UdpServer_Receive(object sender, ReceiveEventArgs e)
{
    //UI表示用メッセージを作成
    string receiveBuf = "Receive:" + e.Message;
    //UI変更はInvokeで実行する
    this.Invoke(new UiControlData(ServerReceiveUiAdd), (object)receiveBuf);
}
インスタンス生成後には下記のようにイベントの追加処理が必要にります。
private delegate void UiControlData(object obj);
以上の処理で非同期処理で、UDPプロトコルによるデータ送受信が可能です。



