前のセクションのサーバー側コードを修正し、クライアントから送信されるメッセージを連続的に受信できるようにし、マルチスレッド機能を有効にします。
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace TcpServerDemo
{
public partial class Form1 : Form
{
private TcpListener listener;
private TcpClient tcpClient;
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnStartServer_Click(object sender, EventArgs e)
{
Thread acceptThread = new Thread(() =>
{
IPAddress ip = IPAddress.Parse(this.textBoxIP.Text);//IPオブジェクトを生成
listener = new TcpListener(ip, Convert.ToInt32(this.textBoxPort.Text));//TCPリスナーを作成
listener.Start();
this.textBoxInfo.Text = "サーバー起動‑" + DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
tcpClient = listener.AcceptTcpClient();//ブロッキングで接続待ち
this.textBoxInfo.Text = "接続完了‑" + DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
NetworkStream stream = tcpClient.GetStream();
byte[] byteArray = new byte[1024];
while (true)
{
int length = stream.Read(byteArray, 0, 1024);//ストリームのバイト配列をbyteArrayへ読み込み
//lengthはクライアントから送信された実バイト数
string receiveMessage = Encoding.Unicode.GetString(byteArray, 0, length);
this.textBoxInfo.Text = "受信:" + receiveMessage + "-" +
DateTime.Now.ToShortTimeString() + "\r\n" + this.textBoxInfo.Text;
}
});
acceptThread.IsBackground = true;
acceptThread.Start();
}
}
}Code language: C# (cs)
WinForms + TcpClient / TcpListener による実装:
クライアントから自由なテキストを連続送信し、【終了】と入力すると接続を切断しプログラムを終了します
このサンプルは簡易的にマルチスレッドによるUIフリーズを回避していますが、本来の正しい実装は下記の通りです。
Control.CheckForIllegalCrossThreadCalls = false;は推奨されない強引な記述です。正式なコードではInvoke/BeginInvokeを使ってスレッドをまたいでコントロールを更新してください。
1. サーバー側
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
namespace TcpServerDemo
{
public partial class Form1 : Form
{
private TcpListener listener;
private TcpClient tcpClient;
public Form1()
{
InitializeComponent();
// 学習デモ用。本番環境では使用しないでください
Control.CheckForIllegalCrossThreadCalls = false;
}
private void btnStartServer_Click(object sender, EventArgs e)
{
// UIブロック回避のため新規スレッドを起動
new Thread(() =>
{
IPAddress ip = IPAddress.Parse(textBoxIP.Text);
listener = new TcpListener(ip, Convert.ToInt32(textBoxPort.Text));
listener.Start();
AppendLog($"サーバー起動‑{DateTime.Now.ToShortTimeString()}");
tcpClient = listener.AcceptTcpClient();
AppendLog($"クライアント接続‑{DateTime.Now.ToShortTimeString()}");
NetworkStream stream = tcpClient.GetStream();
byte[] byteArray = new byte[1024];
while (true)
{
int length = stream.Read(byteArray, 0, 1024);
if (length <= 0)
{
AppendLog("クライアントが接続を切断しました");
break;
}
string receiveMessage = Encoding.Unicode.GetString(byteArray, 0, length);
AppendLog($"受信:{receiveMessage} ‑{DateTime.Now.ToShortTimeString()}");
}
tcpClient.Close();
listener.Stop();
}).Start();
}
//テキストボックスへログ追記
private void AppendLog(string msg)
{
textBoxInfo.Text = msg + "\r\n" + textBoxInfo.Text;
}
}
}Code language: C# (cs)
2. クライアントコード
連続入力に対応、「終了」入力で通信を終了
クライアント画面に用意するコントロール:
textBoxServerIp:サーバーIPアドレスtextBoxPort:ポート番号textBoxSend:送信メッセージ入力欄btnConnect:接続ボタンbtnSend:送信ボタン
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace TcpClientDemo
{
public partial class ClientForm : Form
{
private TcpClient client;
private NetworkStream stream;
private bool isConnected = false;
public ClientForm()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
//サーバーへ接続
private void btnConnect_Click(object sender, EventArgs e)
{
try
{
client = new TcpClient();
client.Connect(textBoxServerIp.Text, Convert.ToInt32(textBoxPort.Text));
stream = client.GetStream();
isConnected = true;
MessageBox.Show("接続成功、メッセージ送信を開始できます!");
}
catch (Exception ex)
{
MessageBox.Show("接続失敗:" + ex.Message);
}
}
//メッセージ送信処理
private void btnSend_Click(object sender, EventArgs e)
{
if (!isConnected)
{
MessageBox.Show("先にサーバーへ接続してください!");
return;
}
string content = textBoxSend.Text.Trim();
if (string.IsNullOrEmpty(content))
return;
//終了コマンド判定
if (content == "終了")
{
byte[] exitData = Encoding.Unicode.GetBytes(content);
stream.Write(exitData, 0, exitData.Length);
//リソース解放
stream.Close();
client.Close();
isConnected = false;
MessageBox.Show("接続を切断しました");
return;
}
//通常メッセージ送信
byte[] data = Encoding.Unicode.GetBytes(content);
stream.Write(data, 0, data.Length);
textBoxSend.Clear();
}
}
}Code language: C# (cs)
static void Main(string[] args)
{
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 8899);
NetworkStream stream = client.GetStream();
while (true)
{
Console.Write("送信内容を入力:");
string msg = Console.ReadLine();
byte[] buf = Encoding.Unicode.GetBytes(msg);
stream.Write(buf,0,buf.Length);
if (msg == "終了")
{
stream.Close();
client.Close();
break;
}
}
}Code language: JavaScript (javascript)
必要であれば、コード全体を完全非同期 async/await スタイルに書き換え、子スレッドとクロススレッドチェック無効化といった非推奨の実装を廃止できます。
クライアントからの連続送信
Previous: クライアント‑サーバー通信
Next: 連続チャット