2024/06/03 電子書籍「電子書籍出版・技術文書作成を劇的に加速!秀丸エディタ + Markdown + Pandocの驚異」を出版

Indy TIdTCPServerの使い方

C++Builder

TCP/IPを使用したプログラムを作成する場合、以下のページで説明しているコンポーネント(TClientSocket, TServerSocket)を使うのが比較的簡単にプログラムを作成する事が出来ます。

ただ、残念ながらこれらのコンポーネントは非推奨となっており、C++Builder(Delphi)では、Indyが標準でインストールされています。ここでは、TIdTCPServerコンポーネントの使用方法について説明します。TServrSocketに比べると、若干癖があるように感じます。

尚、TIdTCPClient, TIdTCPServerコンポーネントは、VCLでもFMXでも使用出来るコンポーネントです。Android,iOS等で使用出来ますので、今後の事を考えるとTIdTCPClient, TIdTCPServerコンポーネントを使用しておいた方が良いと思います。

TIdTCPServerコンポーネントの使用法を、実際に動作確認用のテストプログラムを作成しながら説明します。実際にプログラムの動作確認を行うには、TIdTCPClient用のテストプログラムも必要となりますので、以下のページも参照ください。

TClientSocket、TServerSocketの使用方法につきましては、以下の記事をご覧ください。

テスト用プロジェクトの作成

  1. C++Builderで、初めてのプロジェクト作成で、説明した「SDIアプリケーション」をベースにテストプログラムを作成します。
  2. プロジェクト名を、”TIdTCPServer_test”に変更します。(プロジェクト名の変更を参照してください。)
  3. メッセージの表示用に、TMemoコンポーネントをDropし、Alignプロパティを”alClient”に設定します。
  4. TIdTCPServerコンポーネントをDropします。
  5. 以下のイベントの追加します。

最初のイベント処理を追加するを参考に、以下のイベントを追加しておきましょう。

イベント説明
OnShowフォームが表示されたとき(フォームの Visible プロパティが true に設定されている場合)に発生します。
OnCloseQuery問い合わせを終了しようとしたときに発生します。
OnCloseフォームを閉じたときに発生します。

プロジェクトファイルのダウンロードはこちらから

TIdTCPServerコンポーネントのイベントの追加

以下の3つのイベントを追加します。

NameDescription
OnConnectEvent handler signalled for establishing new client connections.
OnDisconnectEvent handler signalled when disconnecting the client connection.
OnExceptionEvent handler for exceptions raised in a peer thread.

Indyのヘルプファイル

RAD Studio 11.3 で、インストールフォルダを変更していない場合は、以下のフォルダにヘルプファイルがあります。(ヘルプをインストールしている場合)

C:\Program Files (x86)\Embarcadero\Studio\22.0\Help\Doc\Indy10.chm

TIdTCPServerコンポーネントの接続処理

TIdTCPServerコンポーネントで、サーバー処理を行うには、

  1. DefaultPortに、ポート番号を設定
  2. Activeプロパティをtrue

にします。アプリの起動時に有効にするには、コンストラクタかOnShowイベントに記述します。

__fastcall TSDIAppForm::TSDIAppForm(TComponent *AOwner)
    : TForm(AOwner)
{
    IdTCPServer1->DefaultPort   = 2000;
    IdTCPServer1->Active        = true;
}

TIdTCPServerコンポーネントのイベント内での処理

以下に、各イベント処理について説明します。

OnConnectイベント

クライアントと接続すると発生するイベントです。

void __fastcall TSDIAppForm::IdTCPServer1Connect(TIdContext *AContext)
{
    // クライアントが接続
    Memo1->Lines->Add("IdTCPServer1Connect");
}

OnDisconnectイベント

クライアントとの接続が、切れた時に発生するイベントです。

void __fastcall TSDIAppForm::IdTCPServer1Disconnect(TIdContext *AContext)
{
    // クライアントが切断
    Memo1->Lines->Add("IdTCPServer1Disconnect");
}

OnExceptionイベント

TIdTCPServerコンポーネントでは、OnExceptionイベントでクライアントからの送信データを受信することが出来ます。

クライアント側からの送信データを受信し、Memo1に表示しています。クライアントの接続数は、考慮していません。

データの受信は、IOHandler->ReadBytes()関数を使用します。引数には、TBytes型になります。

受信しているデータのバイト数は、IOHandler->InputBuffer->Sizeで取得出来ます。

TBytesについては、バイトの動的配列 TBytesの使い方を参照してください。

void __fastcall TSDIAppForm::IdTCPServer1Execute(TIdContext *AContext)
{
    // クライアントからのデータを受信
    if( AContext->Connection->IOHandler->Connected() )
    {
        AContext->Connection->IOHandler->CheckForDisconnect(True, True);

        int size = AContext->Connection->IOHandler->InputBuffer->Size;
        if(size != 0)
        {
            TIdBytes bytes;
            AContext->Connection->IOHandler->ReadBytes(bytes, size);

            // -------------------------------
            // 受信データが、ASCIIコードの文字の場合
            String wstr = "";
            for(int i=0;i<bytes.Length;i++)
            {
                wstr += (char)bytes[i];
            }
            Memo1->Lines->Add(wstr);
        }
    }
}

データの送信

簡単に実装するために、ファイルの作成イベント(FileNew1)に、データ送信の処理を追加しました。

データの送信は、IOHandler->Write()関数を使用します。この関数の引数も、TBytes型をとります。

ここでも、クライアントの接続数は、考慮していません。

void __fastcall TSDIAppForm::FileNew1Execute(TObject *Sender)
{
    TIdContext *Context;
    TList *List;
    int Count   = 0;

    List    = IdTCPServer1->Contexts->LockList();
    if(List->Count >= 1)
    {
        try
        {   // ここでは、最初の接続先に送信
            Context = (TIdContext *)(List->Items[Count]);
            try
            {
                char str[]  = "Server Test2";

                TBytes txdata;
                txdata.Length   = sizeof(str);
                for(int i=0;i<sizeof(str);i++)
                {
                    txdata[i]   = (BYTE)str[i];
                }

                Context->Connection->IOHandler->Write(txdata, txdata.Length);
            } catch(...) {
                //
            }
        } __finally {
            IdTCPServer1->Contexts->UnlockList();
        }
    }
}

再接続処理

サーバー側は、接続を待っているだけなので特に再接続の処理はしなくてもクライアントと再接続出来ます。

参考URL

以下のHPも参考にしてください。

タイトルとURLをコピーしました