このレッスンではクライアントを作成し、クライアントからサーバーへ接続を行います。
前回のサーバー側のコード(TcpListener)と今回実装するクライアント(TcpClient)を組み合わせ、手順に沿ってTCPチャットツールを作成していきます。
概念の整理
- サーバー:TcpListener
固定IPと固定ポート(9500)にバインドします。受動的に待ち受けを続け、複数のクライアントからの接続を同時に受け入れられます。店舗が顧客の来店を待つイメージです。 - クライアント:TcpClient
手動でポートを指定する必要はありません。OSがランダムな一時ポートを自動割り当て、サーバーの9500番ポートに対して能動的に接続を開始します。
通信双方のポートは一致しない
クライアント:ランダムポート — サーバー:固定9500
コンソール版クライアント
using System;
using System.Net.Sockets;
namespace TalkClient
{
class Program
{
static void Main(string[] args)
{
// TCPクライアントインスタンス生成
TcpClient tcpClient = new TcpClient();
// ローカルの127.0.0.1:9500サーバーへ接続
// 他のPCの場合は対象マシンのIPを指定。サーバーとクライアントは同一PC上でなくても動作します。
tcpClient.Connect("127.0.0.1", 9500);
// LocalEndPoint:自身のクライアント側アドレスとポート
// RemoteEndPoint:接続先サーバーのアドレスとポート
Console.WriteLine("接続完了。自ポート {0}、サーバーポート{1}",
tcpClient.Client.LocalEndPoint,
tcpClient.Client.RemoteEndPoint);
Console.ReadLine();
tcpClient.Close();
}
}
}Code language: JavaScript (javascript)
WinForms クライアントコード
使用するUIコントロール:
textBoxIP:サーバーIPアドレスtextBoxPort:サーバーポート番号buttonStart:接続ボタンtextBoxInfo:メッセージ表示欄textBoxMsg:送信メッセージ入力欄buttonSend:送信ボタン
using System;
using System.Net.Sockets;
using System.Windows.Forms;
namespace SocketChatClient
{
public partial class Form1 : Form
{
TcpClient tcpClient;
public Form1()
{
InitializeComponent();
}
// 接続ボタンクリックイベント
private void buttonStart_Click(object sender, EventArgs e)
{
tcpClient = new TcpClient();
try
{
string ip = textBoxIP.Text;
int port = Convert.ToInt32(textBoxPort.Text);
tcpClient.Connect(ip, port);
textBoxInfo.AppendText($"接続成功!ローカルエンドポイント:{tcpClient.Client.LocalEndPoint}\r\n");
}
catch (Exception ex)
{
MessageBox.Show("接続失敗‑" + ex.Message);
}
}
}
}Code language: PHP (php)
サーバーとクライアントの連携手順
- 最初にサーバープログラムを起動、開始ボタンを押し
TcpListener.Start()で9500番ポートの待ち受けを開始 - 次にクライアントプログラムを起動、接続ボタンを押すと
TcpClient.Connect()によりTCP3ウェイハンドシェイクが実行されます - 接続確立後は
NetworkStreamを通じて双方向でメッセージの送受信を行います(次回講義)
注意点
- 接続が失敗する主な要因
- 起動順番の誤り:サーバーを先に起動していない
- IPアドレスまたはポート番号の記入ミス
- ファイアウォールによるブロック。複数PCでデバッグする際は
127.0.0.1を使わずLAN内IPを使用してください
- ポートに関する知識
- サーバーは9500番ポートを固定で使用し、複数クライアントからの接続を同時に処理可能
- クライアント側のポートはOSがランダムに割り当て。実行毎に値が変わるため手動指定は不要
- ブロッキングに関する警告
WinForms上で.Connect()を直接呼び出すとUIスレッドがブロックされます。本番環境では非同步のConnectAsyncを利用し、画面フリーズを防ぎましょう。
復習:WinFormsサーバー(前回)
using System;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
namespace SocketChatServer
{
public partial class Form1 : Form
{
IPAddress ip;
TcpListener listener;
public Form1()
{
InitializeComponent();
}
private void buttonStart_Click(object sender, EventArgs e)
{
ip = IPAddress.Parse(textBoxIP.Text);
int port = Convert.ToInt32(textBoxPort.Text);
listener = new TcpListener(ip, port);
listener.Start();
textBoxInfo.Text = $"サーバー起動 {DateTime.Now.ToShortTimeString()}\r\n" + textBoxInfo.Text;
}
}
}Code language: C# (cs)
クライアント
Previous: サーバー側ポート監視
Next: クライアント‑サーバー通信