Visual Studio | WPF > UDP > echo server > v0.1, v0.2

```txt:動作環境
Windows 8.1 Pro (64bit)
Microsoft Visual Studio 2017 Community
```

### 処理の概要

UDPで受信した内容をecho backする。

### 参考

[unity > udp > echo server > client.Client.Blocking = false;](https://qiita.com/7of9/items/1cccd81149d2916510a9)

### code v0.1

```MainWindow.xaml
<Window x:Class="_171109_t1800_udpTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_171109_t1800_udpTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <StackPanel>
            <Button Name="B_connect" Height="30" Width="100" Content="Connect" Click="B_connect_Click"/>
        </StackPanel>
    </Grid>
</Window>
```

```MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// 以下を追加した
using System.Threading;
using System.Net;
using System.Net.Sockets;

/*
 * v0.1 2017/11/09 echo back
 *    - add FuncRcvData()
 *    - add [B_connect]
 */

namespace _171109_t1800_udpTest
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        Thread rcvThr;
        UdpClient client;
        public int port_rcv = 7000;

        public string lastRcvd;
        private bool stopThr = false;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void B_connect_Click(object sender, RoutedEventArgs e)
        {
            this.Title = "Connected";
            rcvThr = new Thread(new ThreadStart(FuncRcvData));
            rcvThr.Start();
        }

        private void FuncRcvData()
        {
            client = new UdpClient(port_rcv);
            client.Client.ReceiveTimeout = 300; // msec
            client.Client.Blocking = false; // UI処理のため
            while(stopThr == false)
            {
                try
                {
                    IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
                    byte[] data = client.Receive(ref anyIP);
                    string text = Encoding.ASCII.GetString(data);
                    lastRcvd = text;

                    client.Send(data, data.Length, anyIP); // echo back
                }
                catch (Exception err)
                {
                    // 何かのエラー処理
                }
            }
        }
    }
}
```

### 動作例

Buttonを押下してConnected状態にする。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/e2faa9bf-2d2f-15cf-2e6a-71e9090b154d.png)

別のPCからUDP(7000)に対して文字列を送る。

[NonSoftさんのUDP/IPテストツール](http://nonsoft.la.coocan.jp/Download/UdpTool/index.html)にて動作確認しました。
使い良いツールです。
提供感謝。

### 関連リンク

[echo serverシリーズ](https://qiita.com/search?q=echo+server+user%3A7of9)

### 所感

WPFは久しぶりすぎていろいろ忘れた。
(鳥頭な7of9 :chicken::chicken::chicken:)

IntelliSense と過去の自分のコード例がないと使いたいものをすぐに作れないだろう。

### code v0.2

- スレッドが動いている場合の終了処理を追加
    - これをしないとConnectボタン押下後に終了すると、プロセスがゾンビ化する
    - XAMLにてWindowタグにClosingを追加
        - Window_Closing()
    - code behindにWindow_Closing()を実装
        - `stopThr = true;`

```MainWindow.xaml
<Window x:Class="_171206_t1027_UDPechoServer.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:_171206_t1027_UDPechoServer"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        Closing="Window_Closing">
    <Grid>
        <StackPanel>
            <Button Name="B_connect" Height="30" Width="100" Content="Connect" Click="B_connect_Click"/>
        </StackPanel>        
    </Grid>
</Window>
```

```MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// 以下を追加した
using System.Threading;
using System.Net;
using System.Net.Sockets;

/*
 * v0.1 2017/11/09 echo back
 *    - add FuncRcvData()
 *    - add [B_connect]
 */

namespace _171206_t1027_UDPechoServer
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        Thread rcvThr;
        UdpClient client;
        public int port_rcv = 7000;

        public string lastRcvd;
        private bool stopThr = false;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void B_connect_Click(object sender, RoutedEventArgs e)
        {
            this.Title = "Connected";
            rcvThr = new Thread(new ThreadStart(FuncRcvData));
            rcvThr.Start();
        }

        private void FuncRcvData()
        {
            client = new UdpClient(port_rcv);
            client.Client.ReceiveTimeout = 300; // msec
            client.Client.Blocking = false; // UI処理のため
            while (stopThr == false)
            {
                try
                {
                    IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
                    byte[] data = client.Receive(ref anyIP);
                    string text = Encoding.ASCII.GetString(data);
                    lastRcvd = text;

                    client.Send(data, data.Length, anyIP); // echo back
                }
                catch (Exception err)
                {
                    // 何かのエラー処理
                }
            }
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            stopThr = true;
        }
    }
}
```