web-dev-qa-db-ja.com

Indy TCPクライアント/サーバー、クライアントはサーバーとして機能

IndyのTIdTCPClientおよびTIdTCPServerは、次のシナリオでどのように使用できますか。

Client  ---------- initate connection -----------> Server
...
Client  <---------------command------------------- Server
Client  ----------------response-----------------> Server
...
Client  <---------------command------------------- Server
Client  ----------------response-----------------> Server

クライアント接続を開始ですが、「サーバー」として機能します(コマンドを待機してコマンドを実行します)。

この場合、OnExecuteTIdTCPServerアプローチはうまく機能しません(少なくとも、うまく機能しません)。どうすればこれができますか?

質問が十分に明確であることを願っています。

19
jpfollenius

IndyのTIdTCPServerコンポーネントでこれを行うことを妨げるものは何もありません。

TIdTCPServerは接続のみをセットアップします。残りは実装する必要があります。そのため、実際の送信と受信のシーケンスは、好きなようにすることができます。

このコードをTIdTCPServerコンポーネントのOnExecuteイベントに配置します。

var
  sName: String;
begin
  // Send command to client immediately after connection
  AContext.Connection.Socket.WriteLn('What is your name?');
  // Receive response from client
  sName := AContext.Connection.Socket.ReadLn;
  // Send a response to the client
  AContext.Connection.Socket.WriteLn('Hello, ' + sName + '.');
  AContext.Connection.Socket.WriteLn('Would you like to play a game?');
  // We're done with our session
  AContext.Connection.Disconnect;
end;

TIdTCPServerを本当に簡単に設定する方法は次のとおりです。

IdTCPServer1.Bindings.Clear;
IdTCPServer1.Bindings.Add.SetBinding('127.0.0.1', 8080);
IdTCPServer1.Active := True;

これにより、ポート8080でループバックアドレスのみをリッスンするようサーバーに指示します。これにより、コンピューターの外部のユーザーがサーバーに接続することを防ぎます。

次に、クライアントを接続するには、Windowsコマンドプロンプトに移動し、次のように入力します。

telnet 127.0.0.1 8080

出力は次のとおりです。

お名前は何ですか?

マーカス

こんにちは、マーカス。

ゲームをプレイしませんか?

ホストへの接続が失われました。

Telnetを持っていないのですか? Vistaおよび7 にTelnetクライアントをインストールする方法は次のとおりです。

またはTIdTCPクライアントを使用すると、これを行うことができます:

var
  sPrompt: String;
  sResponse: String;
begin
  // Set port to connect to
  IdTCPClient1.Port := 8080;
  // Set Host to connect to
  IdTCPClient1.Host := '127.0.0.1';
  // Now actually connect
  IdTCPClient1.Connect;
  // Read the Prompt text from the server
  sPrompt := IdTCPClient1.Socket.ReadLn;
  // Show it to the user and ask the user to respond
  sResponse := InputBox('Prompt', sPrompt, '');
  // Send user's response back to server
  IdTCPClient1.Socket.WriteLn(sResponse);
  // Show the user the server's final message
  ShowMessage(IdTCPClient1.Socket.AllData);
end;

ここで注意すべき重要な点は、ReadLnステートメントがデータが存在するようになるまで待機することです。それがすべての背後にある魔法です。

18
Marcus Adams

コマンドが本質的にテキストである場合は、TIdCmdTCPClientコンポーネントを確認してください。これは、サーバーがクライアントの代わりにコマンドを送信している状況向けに特別に設計されています。サーバーはTIdContext.Connection.IOHandler.WriteLn()またはTIdContext.Connection.IOHandler.SendCmd()を使用してコマンドを送信できます。

7
Remy Lebeau

クライアントがサーバーに接続すると、サーバーにはAContext: TIdContextパラメーターを指定したOnConnectイベントがあります。

このプロパティはAContext.Connectionであり、イベントの外部(たとえば、配列)に格納できます。それをIPまたはより良い生成されたセッションIDとペアリングし、その基準でその接続を参照する場合、サーバーにアドホックコマンドまたはメッセージをクライアントに送信させることができます。

お役に立てれば!

5
LaKraven

通常、クライアントとサーバー側には、着信テレグラムを読み取り、保留中のテレグラムを送信するスレッドがありますが、この種類のプロトコル(送受信、いつ、何を行うか)はアプリケーションによって異なります。

4
Gronfi

サーバーからのメッセージをリッスンするスレッドを使用してクライアント側を実装するための非常に優れた出発点は、Indy Telnetクライアントコンポーネント(プロトコルフォルダーのTIdTelnet)です。

Indy telnetクライアントはtelnetサーバーに接続し、and one socketを使用して書き込みandデータを読み取ります。読み取りはリスナースレッドで行われます。

この設計は、チャットなどの分散メッセージングソフトウェアの構築に簡単に適合させることができ、ブロッキングソケットを使用してプロトコルをネットワークレイヤーから簡単に分離できることも示しています。

3
mjn