WPF
networkApp
myVisualStudioStudy

Visual Studio | WPF > TCPsender (TCP送信と応答受信) > v0.1

More than 1 year has passed since last update.
動作環境
Windows 8.1 Pro (64bit)
Microsoft Visual Studio 2017 Community
Sublime Text 2

TCPで送信して応答を受信する実装をしてみた。

関連

code v0.1

MainWindow.xaml
<Window x:Class="WPF_TCPClient_171205.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:WPF_TCPClient_171205"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid Background="LightGray">
        <Button Name="B_send" Content="Send" HorizontalAlignment="Left" Margin="432,67,0,0" 
                VerticalAlignment="Top" Width="75" Click="B_send_Click"/>
        <Label Content="Text" HorizontalAlignment="Left" Margin="10,64,0,0" VerticalAlignment="Top"/>
        <TextBox Name="T_sendText" HorizontalAlignment="Left" Height="23" Margin="58,65,0,0" 
                 TextWrapping="Wrap" Text="Hello" VerticalAlignment="Top" Width="357"/>
        <TextBox Name="T_log" HorizontalAlignment="Left" Height="215" Margin="10,94,0,0" 
                 TextWrapping="Wrap" VerticalAlignment="Top" Width="497"
                 VerticalScrollBarVisibility="Visible"
                 Text="{Binding LogText}"/>
        <Label Content="SendTo" HorizontalAlignment="Left" Margin="10,9,0,0" VerticalAlignment="Top"/>
        <TextBox Name="T_sendTo" HorizontalAlignment="Left" Height="23" Margin="68,10,0,0" 
                 TextWrapping="Wrap" Text="192.168.0.79" VerticalAlignment="Top" Width="120"/>
        <Label Content="port" HorizontalAlignment="Left" Margin="229,9,0,0" VerticalAlignment="Top"/>
        <TextBox Name="T_port" HorizontalAlignment="Left" Height="23" Margin="268,10,0,0" 
                 TextWrapping="Wrap" Text="7000" VerticalAlignment="Top" Width="120"/>

    </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.Net;
using System.Net.Sockets;
using System.Threading;
using System.ComponentModel;
using System.IO;

namespace WPF_TCPClient_171205
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        static private TcpClient s_tcpClient;
        static private string _logText = string.Empty;

        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = this;
        }

        private bool TCP_connect(string ipAddress, string portStr)
        {
            if (int.TryParse(portStr, out int portInt) == false)
            {
                return false;
            }
            s_tcpClient = new TcpClient(ipAddress, portInt);
            s_tcpClient.Client.ReceiveTimeout = 300; // msec
            s_tcpClient.Client.Blocking = true; // *** 1 
            return true;
        }
        private void TCP_disconnect()
        {
            s_tcpClient.Close();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName = null)
        {
            if (PropertyChanged != null)
                PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public string LogText
        {
            get { return _logText; }
            set
            {
                _logText = value;
                OnPropertyChanged("LogText");
            }
        }

        private void TCP_send(string ipadr, string portStr, string text)
        {
            if (int.TryParse(portStr, out int portInt) == false)
            {
                return; // error
            }
            if (TCP_connect(T_sendTo.Text, T_port.Text) == false)
            {
                return; // error
            }

            using (var netStream = s_tcpClient.GetStream())
            {
                using (var sWriter = new StreamWriter(netStream, Encoding.ASCII))
                {
                    // 1. 送信
                    sWriter.WriteLine(text);
                    sWriter.Flush();

                    // 2. 受信
                    ReceiveData(netStream);
                }
            }
            TCP_disconnect();
        }

        private void ReceiveData(NetworkStream netStream)
        {
            // 1. rcvdは<CR><LF>付き
            byte[] ReceiveBytes = new byte[1024];
            int BytesReceived = netStream.Read(ReceiveBytes, 0, ReceiveBytes.Length);
            string rcvd = Encoding.ASCII.GetString(ReceiveBytes, 0, BytesReceived);

            // 2. rcvdは<CR><LF>なし
            //var sReader = new StreamReader(netStream, Encoding.ASCII);
            //string rcvd = sReader.ReadLine();

            //
            LogText += rcvd;
        }

        private void B_send_Click(object sender, RoutedEventArgs e)
        {
            TCP_send(T_sendTo.Text, T_port.Text, T_sendText.Text);
        }
    }
}

実行例

接続先にはVisual Studio | WPF > TCPサーバ > echo server > 1対N通信 > ThreadPool.QueueUserWorkItem()使用 v0.1, v0.2
のソフトを起動し、Listenボタンを押しておく。

実行結果は以下のようになる。
qiita.png

備考

受信処理

受信処理はReceiveData()の2種類の処理で受信できている。
1の場合(Read)ではCR,LFのコード付きでLogTextに入る。
2の場合(ReadLine)ではCR, LFのコードなしでLogTextに入る。

Blocking

s_tcpClient.Client.Blockingをtrueとしている。
falseにするとGetStream()においてエラーが出る。

System.IO.IOException: '操作は非ブロッキング ソケットでは実行できません。'