C#でTCPClientを使用したタイムアウト時間の設定方法

2024年12月23日月曜日

C#

t f B! P L

C#でTCPクライアント通信を行う際、ネットワークの遅延やサーバーの応答がない場合に備えて、タイムアウト時間を設定することが一般的です。TcpClientクラスでは、送信時と受信時のタイムアウトはSendTimeoutReceiveTimeoutプロパティを使って容易に設定できますが、接続タイムアウトに関しては直接的に指定するプロパティがありません。そのため、Taskクラスの非同期操作を利用して接続タイムアウトを実現します。この記事では、これらのタイムアウト設定方法を詳しく解説します。

TCP通信におけるタイムアウト

タイムアウトは、指定した時間内に通信が完了しない場合に操作を中断し、例外をスローする仕組みです。通信の遅延や障害に備えるため、以下のポイントでタイムアウトを設定することで、遅延した処理を迅速に中断できます。

タイムアウトの設定 内容
接続タイムアウト サーバーへの接続が確立されるまでの待機時間。
送信タイムアウト データ送信が完了するまでの待機時間。<br />SendTimeoutプロパティ
受信タイムアウト データ受信が完了するまでの待機時間。<br />ReceiveTimeoutプロパティ

2. サンプルコード

以下は、TcpClientを使用してタイムアウトを設定する例です。

using System;
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        // サーバーのIPアドレスとポート番号を設定
        string serverIp = "127.0.0.1";
        int serverPort = 12345;

        // TcpClientの作成
        using (TcpClient client = new TcpClient())
        {
            try
            {
                // 接続タイムアウトの設定(非同期接続を利用)
                var connectTask = client.ConnectAsync(serverIp, serverPort);
                if (await Task.WhenAny(connectTask, Task.Delay(5000)) == connectTask)
                {
                    // 接続成功
                    Console.WriteLine("サーバーに接続しました。");
                }
                else
                {
                    // タイムアウト
                    throw new TimeoutException("接続がタイムアウトしました。");
                }

                // タイムアウトの設定
                client.SendTimeout = 5000; // 送信タイムアウト(ミリ秒)
                client.ReceiveTimeout = 5000; // 受信タイムアウト(ミリ秒)

                // ネットワークストリームの取得
                using (NetworkStream stream = client.GetStream())
                {
                    // データの送信
                    string message = "Hello, Server!";
                    byte[] dataToSend = Encoding.UTF8.GetBytes(message);
                    await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
                    Console.WriteLine("データを送信しました。");

                    // データの受信
                    byte[] buffer = new byte[1024];
                    int receivedBytes = await stream.ReadAsync(buffer, 0, buffer.Length);
                    string receivedMessage = Encoding.UTF8.GetString(buffer, 0, receivedBytes);
                    Console.WriteLine("受信したデータ: " + receivedMessage);
                }
            }
            catch (TimeoutException ex)
            {
                Console.WriteLine("タイムアウトエラー: " + ex.Message);
            }
            catch (IOException ex)
            {
                Console.WriteLine("入出力エラー: " + ex.Message);
            }
            catch (SocketException ex)
            {
                Console.WriteLine("ソケットエラー: " + ex.Message);
            }
        }
    }
}

コードの解説(接続タイムアウトの実現方法)

TcpClientクラスには、接続タイムアウトを直接指定するプロパティがありません。そのため、非同期接続とTask.Delayを組み合わせることで、接続タイムアウトを設定します。以下はその手順です。

  1. 非同期接続の開始 TcpClient.ConnectAsyncメソッドを使用して、接続を非同期で実行します。
  2. Task.Delay との組み合わせ** Task.WhenAnyを使用して、接続操作と指定時間のタイムアウトタスクのどちらが先に完了するかを確認します。接続タスクが完了する前にタイムアウトタスクが終了した場合、接続がタイムアウトしたとみなします。

サンプルコードの一部

var connectTask = client.ConnectAsync(serverIp, serverPort);
if (await Task.WhenAny(connectTask, Task.Delay(5000)) == connectTask)
{
    // 接続成功
    Console.WriteLine("サーバーに接続しました。");
}
else
{
    // タイムアウト
    throw new TimeoutException("接続がタイムアウトしました。");
}

この方法により、指定した時間内に接続が確立されなかった場合に例外をスローできます。

4. 注意点

  • タイムアウト時間は、ネットワーク環境や用途に応じて適切に設定してください。短すぎる場合、正常な通信でもタイムアウトになる可能性があります。
  • 接続時のタイムアウト処理は、非同期操作を利用するのが一般的です。
  • タイムアウト処理を適切に実装することで、アプリケーションが応答しなくなるリスクを軽減できます。

まとめ

この記事では、C#でTcpClientを使用したタイムアウト設定方法を解説しました。適切なタイムアウト設定を行うことで、ネットワーク通信の安定性とアプリケーションの堅牢性を向上させることができます。ぜひ、プロジェクトに取り入れてみてください。

スポンサーリンク
スポンサーリンク

このブログを検索

Profile

自分の写真
Webアプリエンジニア。 日々新しい技術を追い求めてブログでアウトプットしています。
プロフィール画像は、猫村ゆゆこ様に書いてもらいました。

仕事募集もしていたり、していなかったり。

QooQ