DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

TCPクライアント・サーバープログラムを作成する

TCPサーバーはTcpListenerクラスを、TCPクライアントはTcpClientクラスを使用してプログラムを作成します。Socketクラスを使用した方法も考えられますが、これについては「TCPを利用した複数クライアント接続可能なチャットアプリケーションを作る」で説明しています(非同期処理に関しても、こちらで説明しています)。

TCP(Transmission Control Protocol)を使ったアプリケーションは、サーバーとクライアントが必要です。サーバーは指定されたポートを監視し、クライアントの接続要求を待ちます。クライアントからの接続要求があり、これをサーバーが受け付けると、接続が完了し、切断するまでの間、データの送受信が可能となります。(TCPの詳細については、「アスキー デジタル用語辞典 - TCP」などをご覧ください。)

TCPサーバーの作成

まずは、TCPサーバーの作成法から説明します。手順は次のようになります。

  1. TcpListenerクラスのStartメソッドによりListen(監視)を開始し、接続要求を待機します。
  2. 続いてAcceptTcpClientメソッドにより、クライアントの接続要求を受け入れます。
  3. AcceptTcpClientメソッドで返されるTcpClientオブジェクトのGetStreamメソッドによりNetworkStreamを取得し、データの送受信にはこのNetworkStreamを使用します。

以下に示すコンソールアプリケーションは、ローカルIPアドレスのポート2001で動作し、まず接続してきたクライアントからデータ(文字列)を受信し、受信した文字列の長さを返信してから、クライアントを切断します。その後サーバーはすぐに終了します(もし終了させずにListenを継続するには、リスナを閉じずに、再びAcceptTcpClientメソッドを呼び出してください)。

VB.NET
コードを隠すコードを選択
Imports System

Class Server
    'エントリポイント
    Public Shared Sub Main()
        '文字コードを指定する
        Dim enc As System.Text.Encoding = System.Text.Encoding.UTF8

        'ローカルIPアドレスでListenを開始する
        Dim host As String = "localhost"
        Dim port As Integer = 2001
        Dim ipAdd As System.Net.IPAddress = _
            System.Net.Dns.Resolve(host).AddressList(0)
        Dim listener As New System.Net.Sockets.TcpListener(ipAdd, port)
        listener.Start()
        Console.WriteLine("Port{0}のListenを開始しました。", port)

        '接続要求があったら受け入れる
        Dim tcp As System.Net.Sockets.TcpClient = _
            listener.AcceptTcpClient()
        Console.WriteLine("クライアントが接続しました。")
        'NetworkStreamを取得
        Dim ns As System.Net.Sockets.NetworkStream = tcp.GetStream()

        'クライアントから送られたデータを受信する
        Dim ms As New System.IO.MemoryStream
        Dim resBytes(256) As Byte
        Dim resSize As Integer
        Do
            'データの一部を受信する
            resSize = ns.Read(resBytes, 0, resBytes.Length)
            'Readが0を返した時はクライアントが切断したと判断
            If resSize = 0 Then
                Console.WriteLine("クライアントが切断しました。")
                Console.ReadLine()
                Return
            End If
            '受信したデータを蓄積する
            ms.Write(resBytes, 0, resSize)
        Loop While ns.DataAvailable
        '受信したデータを文字列に変換
        Dim resMsg As String = enc.GetString(ms.ToArray())
        ms.Close()
        Console.WriteLine(resMsg)

        'クライアントにデータを送信する
        Dim sendMsg As String = resMsg.Length.ToString() + "文字"
        '文字列をByte型配列に変換
        Dim sendBytes As Byte() = enc.GetBytes(sendMsg)
        'データを送信する
        ns.Write(sendBytes, 0, sendBytes.Length)
        Console.WriteLine(sendMsg)

        '閉じる
        ns.Close()
        tcp.Close()
        Console.WriteLine("切断しました。")

        'リスナを閉じる
        listener.Stop()
        Console.WriteLine("Listenerを閉じました。")

        Console.ReadLine()
    End Sub
End Class
C#
コードを隠すコードを選択
using System;

class Server
{

    //エントリポイント
    public static void Main() 
    {
        //文字コードを指定する
        System.Text.Encoding enc = System.Text.Encoding.UTF8;

        //ローカルIPアドレスでListenを開始する
        string host = "localhost";
        int port = 2001;
        System.Net.IPAddress ipAdd =
            System.Net.Dns.Resolve(host).AddressList[0];
        System.Net.Sockets.TcpListener listener =
            new System.Net.Sockets.TcpListener(ipAdd, port);
        listener.Start();
        Console.WriteLine("Port{0}のListenを開始しました。", port);

        //接続要求があったら受け入れる
        System.Net.Sockets.TcpClient tcp = listener.AcceptTcpClient();
        Console.WriteLine("クライアントが接続しました。");
        //NetworkStreamを取得
        System.Net.Sockets.NetworkStream ns = tcp.GetStream();
    
        //クライアントから送られたデータを受信する
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        byte[] resBytes = new byte[256];
        int resSize;
        do
        {
            //データの一部を受信する
            resSize = ns.Read(resBytes, 0, resBytes.Length);
            //Readが0を返した時はクライアントが切断したと判断
            if (resSize == 0)
            {
                Console.WriteLine("クライアントが切断しました。");
                Console.ReadLine();
                return;
            }
            //受信したデータを蓄積する
            ms.Write(resBytes, 0, resSize);
        } while (ns.DataAvailable);
        //受信したデータを文字列に変換
        string resMsg = enc.GetString(ms.ToArray());
        ms.Close();
        Console.WriteLine(resMsg);

        //クライアントにデータを送信する
        string sendMsg = resMsg.Length.ToString() + "文字";
        //文字列をByte型配列に変換
        byte[] sendBytes = enc.GetBytes(sendMsg);
        //データを送信する
        ns.Write(sendBytes, 0, sendBytes.Length);
        Console.WriteLine(sendMsg);

        //閉じる
        ns.Close();
        tcp.Close();
        Console.WriteLine("切断しました。");

        //リスナを閉じる
        listener.Stop();
        Console.WriteLine("Listenerを閉じました。");

        Console.ReadLine();
    }
}

TCPクライアントの作成

次はTCPクライアントを作成する方法です。手順は、次の通りです。

  1. TcpClientクラスのコンストラクタ(あるいはConnectメソッド)によりサーバーと接続します。
  2. サーバーとの接続に成功したところで、TcpClientクラスのGetStreamメソッドによりNetworkStreamを取得し、データの送受信を行います。

以下に示すコンソールアプリケーションは、ローカルIPアドレスのポート2001に接続した後、入力された文字列をサーバーに送信し(キーボードから文字列を入力し、Enterキーを押す)、サーバーから送られてくるデータを受信します。

VB.NET
コードを隠すコードを選択
Imports System

Public Class Client
    Shared Sub Main()
        '文字コードを指定する
        Dim enc As System.Text.Encoding = System.Text.Encoding.UTF8

        'サーバーのホスト名とポート番号
        Dim host As String = "localhost"
        Dim port As Integer = 2001

        'TcpClientを作成し、サーバーと接続する
        Dim tcp As New System.Net.Sockets.TcpClient(host, port)
        Console.WriteLine("サーバーと接続しました。")

        'NetworkStreamを取得する
        Dim ns As System.Net.Sockets.NetworkStream = tcp.GetStream()

        'サーバーにデータを送信する
        '送信するデータを入力
        Dim sendMsg As String = Console.ReadLine()
        '何も入力されなかった時は切断する
        If sendMsg = "" Then
            tcp.Close()
            Return
        End If
        '文字列をByte型配列に変換
        Dim sendBytes As Byte() = enc.GetBytes(sendMsg)
        'データを送信する
        ns.Write(sendBytes, 0, sendBytes.Length)
        Console.WriteLine(sendMsg)

        'サーバーから送られたデータを受信する
        Dim ms As New System.IO.MemoryStream
        Dim resBytes(256) As Byte
        Dim resSize As Integer
        Do
            'データの一部を受信する
            resSize = ns.Read(resBytes, 0, resBytes.Length)
            'Readが0を返した時はサーバーが切断したと判断
            If resSize = 0 Then
                Console.WriteLine("サーバーが切断しました。")
                Console.ReadLine()
                Return
            End If
            '受信したデータを蓄積する
            ms.Write(resBytes, 0, resSize)
        Loop While ns.DataAvailable
        '受信したデータを文字列に変換
        Dim resMsg As String = enc.GetString(ms.ToArray())
        ms.Close()
        Console.WriteLine(resMsg)

        '閉じる
        ns.Close()
        tcp.Close()
        Console.WriteLine("切断しました。")

        Console.ReadLine()
    End Sub
End Class
C#
コードを隠すコードを選択
using System;

public class Client
{
    static void Main()
    {
        //文字コードを指定する
        System.Text.Encoding enc = System.Text.Encoding.UTF8;

        //サーバーのホスト名とポート番号
        string host = "localhost";
        int port = 2001;

        //TcpClientを作成し、サーバーと接続する
        System.Net.Sockets.TcpClient tcp =
            new System.Net.Sockets.TcpClient(host, port);
        Console.WriteLine("サーバーと接続しました。");

        //NetworkStreamを取得する
        System.Net.Sockets.NetworkStream ns = tcp.GetStream();

        //サーバーにデータを送信する
        //送信するデータを入力
        string sendMsg = Console.ReadLine();
        //何も入力されなかった時は切断する
        if (sendMsg == "")
        {
            tcp.Close();
            return;
        }
        //文字列をByte型配列に変換
        byte[] sendBytes = enc.GetBytes(sendMsg);
        //データを送信する
        ns.Write(sendBytes, 0, sendBytes.Length);
        Console.WriteLine(sendMsg);

        //サーバーから送られたデータを受信する
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        byte[] resBytes = new byte[256];
        int resSize;
        do
        {
            //データの一部を受信する
            resSize = ns.Read(resBytes, 0, resBytes.Length);
            //Readが0を返した時はサーバーが切断したと判断
            if (resSize == 0)
            {
                Console.WriteLine("サーバーが切断しました。");
                Console.ReadLine();
                return;
            }
            //受信したデータを蓄積する
            ms.Write(resBytes, 0, resSize);
        } while (ns.DataAvailable);
        //受信したデータを文字列に変換
        string resMsg = enc.GetString(ms.ToArray());
        ms.Close();
        Console.WriteLine(resMsg);

        //閉じる
        ns.Close();
        tcp.Close();
        Console.WriteLine("切断しました。");

        Console.ReadLine();
    }
}
  • 履歴:
  • 2011/3/1 NetworkStream.Closeを呼び出すように修正。

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • このサイトで紹介されているコードの多くは、例外処理が省略されています。例外処理については、こちらをご覧ください。