グローバル変数がうまく行かなかった
C#初めて3日経ちましたがアプリ開発でグローバル変数がうまく使えず半日つぶしたので、Aiに頼ってみました。
サーバー側
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp2
{
public partial class Form1 : Form
{
private TcpListener listener;
private CancellationTokenSource cts;
private TcpClient connectedClient;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
// サーバーをTaskで非同期に起動
cts = new CancellationTokenSource();
Task.Run(() => StartTcpClient(cts.Token));
}
public async void StartTcpClient(CancellationToken token)
{
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 11000);
listener.Start();
AppendText("Server started. Waiting for a connection...");
try
{
while (!token.IsCancellationRequested)
{
connectedClient = await listener.AcceptTcpClientAsync();
AppendText("Client connected!");
// クライアントのメッセージを受信
Task.Run(() => RecvTcpClient(connectedClient, token));
}
}
catch (Exception ex)
{
AppendText($"Exception: {ex.Message}");
}
}
public void StopTcpClient()
{
cts.Cancel();
listener.Stop();
AppendText("Server stopped.");
}
public async void RecvTcpClient(TcpClient client, CancellationToken token)
{
NetworkStream stream = client.GetStream();
byte[] buffer = new byte[1024];
int bytesRead;
try
{
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length, token)) != 0)
{
string receivedData = Encoding.ASCII.GetString(buffer, 0, bytesRead);
AppendText($"Received: {receivedData}");
// 受信したメッセージを返送
// byte[] responseData = Encoding.ASCII.GetBytes("Message received");
//await stream.WriteAsync(responseData, 0, responseData.Length, token);
//AppendText("Sent: Message received");
}
}
catch (Exception ex)
{
AppendText($"Exception: {ex.Message}");
}
finally
{
client.Close();
AppendText("Client disconnected.");
}
}
private void button2_Click(object sender, EventArgs e)
{
string message = textBox1.Text;
SendMessageToClient(message);
}
public async void SendMessageToClient(string message)
{
if (connectedClient != null && connectedClient.Connected)
{
NetworkStream stream = connectedClient.GetStream();
byte[] msg = Encoding.ASCII.GetBytes(message);
await stream.WriteAsync(msg, 0, msg.Length);
AppendText($"Sent to client: {message}");
}
else
{
AppendText("No client connected.");
}
}
private void AppendText(string text)
{
if (InvokeRequired)
{
Invoke((Action)(() => label1.Text = text + Environment.NewLine));
}
else
{
label1.Text=text + Environment.NewLine;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
StopTcpClient();
}
}
}
クライアント側
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
private TcpClient client;
private NetworkStream stream;
public Form1()
{
InitializeComponent();
}
// クライアントとしてサーバーに接続する
public async void Connect()
{
try
{
client = new TcpClient("127.0.0.1", 11000);
stream = client.GetStream();
AppendText("Connected to server.");
// サーバーからのメッセージを非同期で受信
await Task.Run(() => Recv());
}
catch (Exception ex)
{
AppendText($"Exception: {ex.Message}");
}
}
// tcpクライアントにメッセージを送信するメソッドを非同期で実行する
private void button2_Click(object sender, EventArgs e)
{
Send();
}
// tcpクライアントにメッセージを送信する
public async void Send()
{
if (client != null && client.Connected)
{
string message = textBox1.Text;
byte[] data = Encoding.ASCII.GetBytes(message);
try
{
await stream.WriteAsync(data, 0, data.Length);
AppendText($"Sent: {message}");
}
catch (Exception ex)
{
AppendText($"Exception: {ex.Message}");
}
}
else
{
AppendText("Client is not connected.");
}
}
// tcpクライアントからメッセージを受信する
public async void Recv()
{
byte[] buffer = new byte[1024];
int bytesRead;
try
{
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) != 0)
{
string receivedData = Encoding.ASCII.GetString(buffer, 0, bytesRead);
AppendText($"Received: {receivedData}");
}
}
catch (Exception ex)
{
AppendText($"Exception: {ex.Message}");
}
}
private void AppendText(string text)
{
if (InvokeRequired)
{
Invoke((Action)(() => label1.Text = text + Environment.NewLine));
}
else
{
label1.Text = text + Environment.NewLine;
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (client != null)
{
client.Close();
}
}
private void button1_Click_1(object sender, EventArgs e)
{
Connect();
}
}
}
説明
サーバー側
Form1_Load:
フォームがロードされたときにサーバーを非同期に起動します。
StartTcpClient:
TcpListenerを初期化し、クライアントの接続を待機します。
接続されたクライアントごとにRecvTcpClientを非同期に実行します。
StopTcpClient:
サーバーを停止し、CancellationTokenSourceをキャンセルします。
RecvTcpClient:
クライアントからのメッセージを受信し、受信したメッセージを返送します。
受信したメッセージはテキストボックスに表示されます。
button2_Click:
ボタンがクリックされたときに、テキストボックスの内容をクライアントに送信します。
SendMessageToClient:
クライアントにメッセージを送信します。クライアントが接続されていない場合は、その旨を表示します。
AppendText:
テキストボックスにテキストを追加します。スレッドセーフな方法でUIを更新するためにInvokeを使用しています。
Form1_FormClosing:
フォームが閉じられるときにサーバーを停止します。
クライアント側
Connectメソッド:
サーバーに接続します。接続が成功すると、サーバーからのメッセージを非同期で受信するタスクを開始します。
Sendメソッド:
テキストボックスに入力されたメッセージをサーバーに送信します。非同期で実行され、メッセージが送信されたことを確認します。
Recvメソッド:
サーバーからのメッセージを非同期で受信し、受信したメッセージをテキストボックスに表示します。
AppendTextメソッド:
スレッドセーフにテキストボックスにテキストを追加します。
Form1_FormClosingメソッド:
フォームが閉じられるときにクライアント接続をクローズします。
button1_Clickメソッド:
サーバーに接続するためのボタンのクリックイベントハンドラです。