9
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Delphi 素朴なソケット通信をしたい

Posted at

はじめに

測定装置など、ハードウェアとの通信にTCP/IPを用いる場合は、ソケットの挙動について、細かな制御が必要がある場合が未だあるように思います。

Delphi XE のTTcpServerは、文字列受信後に直ぐにコネクションを閉じてしまう為、今回はIndy の TIdTCPServer を使用してみました。

(備忘録です)

サンプル

フォーム

![フォームデザイン.png](https://qiita-image-store.s3.amazonaws.com/0/33684/24a57384-4f3c-5fcf-047e-07dc26479966.png)

ソースコード

```delphi unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, IdContext, Vcl.StdCtrls,
IdBaseComponent, IdComponent, IdCustomTCPServer, IdTCPServer, Vcl.ExtCtrls, IdGlobal;

type
TForm1 = class(TForm)
LabeledEdit1: TLabeledEdit;
IdTCPServer1: TIdTCPServer;
CheckBox1: TCheckBox;
Memo1: TMemo;
procedure IdTCPServer1Execute(AContext: TIdContext);
procedure IdTCPServer1Exception(AContext: TIdContext;
AException: Exception);
procedure IdTCPServer1Disconnect(AContext: TIdContext);
procedure IdTCPServer1Connect(AContext: TIdContext);
procedure CheckBox1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private 宣言 }
FEncoding:TEncoding;
public
{ Public 宣言 }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
FEncoding := TEncoding.GetEncoding(932);
Memo1.Clear;
LabeledEdit1.Text := IntToStr(IdTCPServer1.DefaultPort);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
if IdTCPServer1.Active then
IdTCPServer1.Active := False;

FEncoding.Free;
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
if CheckBox1.Checked then begin
CheckBox1.Caption := 'Start';
IdTCPServer1.DefaultPort := StrToInt(LabeledEdit1.Text);
IdTCPServer1.Active := True;
end else begin
CheckBox1.Caption := 'Stop';
IdTCPServer1.Active := False;
end;
end;

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
Memo1.Lines.Add('Connect:'+AContext.Binding.PeerIP);
end;

procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
begin
Memo1.Lines.Add('Disconnect:'+AContext.Binding.PeerIP);
end;

procedure TForm1.IdTCPServer1Exception(AContext: TIdContext;
AException: Exception);
begin
Memo1.Lines.Add(AException.Message);
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
Text: String;
Bytes: TIdBytes;
begin
AContext.Connection.IOHandler.ReadBytes(Bytes,-1);

try
Text := FEncoding.GetString(Bytes);
Memo1.Lines.Add(Text);

AContext.Connection.IOHandler.Write('OK');

except
Memo1.Lines.Add('文字列変換に失敗しました');
end;

end;

end.


<h2>結果</h2>
汎用のソケット通信ツールを使用して、接続したり、文字を送ってみてください。
![こんな感じ.png](https://qiita-image-store.s3.amazonaws.com/0/33684/020e8a1a-3f8f-b51e-9ec2-6e05a47a9352.png)

上記例は、<b>汎用ツール側</b>で、
 1.接続→「あいうえお」送信→切断
 2.接続→「かきくけこ」送信→アプリ終了
を行いました。
2.の後に、もう再度接続する事も可能です。

<h1>ポイント</h1>
<h2>Usesの追加</h2>
「IdGlobal」は手動Usesに追加する必要があるようです。

<h2>受信時の処理</h2>
こちらの記事を参考に、TIdTCPServerのExcecuteイベントにて、受信バッファをバイト列で取出し、Stringに変換します。
http://www.watercolor-city.net/ct_delphi/delphi_tiburon/doc_unicode/bintostring.htm

```delphi
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  Text: String;
  Bytes: TIdBytes;
begin
  AContext.Connection.IOHandler.ReadBytes(Bytes,-1);

  try
    Text := FEncoding.GetString(Bytes);
    Memo1.Lines.Add(Text);

    AContext.Connection.IOHandler.Write('OK');
  except
    Memo1.Lines.Add('文字列変換に失敗しました');
  end;

end;

ReadBytesの2番目の引数は、取得バイト数で、-1に設定すると「前回の取得から全て」となるようです。便利!

今回は、TEncoding のインスタンスをFormCreate内で作成しています。
コードページには、932(Microsoft コードページ Shift-JIS)を指定します。

クライアントの区別

AContext.Binding.PeerIP で IP を取得できるようです。

(自分への)宿題

「接続中の任意のクライアントに、自発的にデータ送信する」場合の処理が、まだ調べられていません。どこからアクセスするのか・・英語・・ニガテ・・。
9
7
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?