Jump to content
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr ×
과거의 기술자료(읽기 전용): https://tech.devgear.co.kr

TCP 방식으로 서버와 클라이언트 간에 메시지 주고 받는 방법 소개


Recommended Posts

이전 글에서 소개한 UDP 통신은 서버와 클라이언트 간에 연결을 지속 할 필요가 없는 방식이고

이번에 소개하는 TCP 방식은 연결이 유지 된 상태에서 메시지를 주고 받는 방식 입니다.

UDP 통신 관련 게시글 보기

image.png

샘플로 제작한 프로젝트는 편의상 서버와 클라이언트를 하나로 합친 상태 입니다. 필요시 서버와 클라이언트를 분리하여 별도의 앱으로 제작 하면 됩니다.

클라이언트는 TIdTCPClient 서버는 IdTCPServer 컴포넌트를 사용 합니다.

메시지를 수신 받는 서버쪽에서 OnConnect / OnExcute / OnDisconnect 이벤트를 생성 하여 아래 소스 처럼 입력 합니다.

클라이언트에서는 TMyThread 클래스를 사용하고 서버는 TMyNotify 클래스를 사용 합니다.

전체 소스 보기

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IdContext, StdCtrls, IdTCPConnection, IdTCPClient, IdBaseComponent,
  IdComponent, IdCustomTCPServer, IdTCPServer, IdSync;

type
  TForm1 = class(TForm)
    IdTCPServer1: TIdTCPServer;
    GroupBox1: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Memo1: TMemo;
    Edit1: TEdit;
    Button1: TButton;
    Button2: TButton;
    Edit2: TEdit;
    Button3: TButton;
    IdTCPClient1: TIdTCPClient;
    GroupBox2: TGroupBox;
    Memo2: TMemo;
    Label3: TLabel;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure IdTCPServer1Execute(AContext: TIdContext);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure IdTCPServer1Connect(AContext: TIdContext);
    procedure IdTCPServer1Disconnect(AContext: TIdContext);
    procedure FormDestroy(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;


  TMyNotify = class(TIdNotify)
  protected
    FMsg: String;
    procedure DoNotify; override;
  public
    constructor Create(const AMsg: String); reintroduce;
    class procedure AddTextToMemo(const AMsg: String);
  end;

  TMyThread = class(TThread)
  private
    FResponse: string;
    FClient: TIdTCPClient;
  protected
    procedure Execute; override;
    procedure UpdateMemo;
  public
    constructor Create(AClient: TIdTCPClient);
  end;


var
  Form1: TForm1;
  MyThread: TMyThread = nil;

implementation

{$R *.dfm}

{ TMyNotify }
//***********************************************************************
constructor TMyNotify.Create(const AMsg: String);
begin
  inherited Create;
  FMsg := AMsg;
end;

procedure TMyNotify.DoNotify;
begin
  Form1.Memo2.Lines.Add(FMsg);
end;

class procedure TMyNotify.AddTextToMemo(const AMsg: String);
begin
  TMyNotify.Create(AMsg).Notify;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if not IdTCPClient1.Connected then
  begin
    IdTCPClient1.Host := Edit1.Text;
    IdTCPClient1.Port := 65535;
    IdTCPClient1.Connect;
    try
      MyThread := TMyThread.Create(IdTCPClient1);       // 대기 스레드 생성
      Edit2.SetFocus;

    except
      IdTCPClient1.Disconnect;
      raise;
    end;
  end;
end;

{ TMyThread }
//**************************************************************
constructor TMyThread.Create(AClient: TIdTCPClient);
begin
  inherited Create(false);

  FClient := AClient;
  FResponse := '';
end;

procedure TMyThread.UpdateMemo;
begin
  if FResponse <> '' then
    Form1.Memo1.Lines.Add('Server: ' + FResponse);
end;

procedure TMyThread.Execute;
begin
  while not Terminated do
  begin
    FResponse := FClient.IOHandler.ReadLn();
    Synchronize(UpdateMemo);
  end;
end;

//*********************************************************
procedure TForm1.Button2Click(Sender: TObject);
begin
  if MyThread <> nil then
    MyThread.Terminate;
  try
    IdTCPClient1.Disconnect;
  finally
    if MyThread <> nil then
    begin
      MyThread.WaitFor;
      MyThread.Free;
      MyThread := nil;
    end;
  end;
end;

procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
  TMyNotify.AddTextToMemo('Connected from: IP' + AContext.Binding.PeerIP +  ' Port: ' + IntToStr(AContext.Binding.Port) + ' / ' +
    IntToStr(AContext.Binding.PeerPort));
end;

procedure TForm1.IdTCPServer1Disconnect(AContext: TIdContext);
begin
  TMyNotify.AddTextToMemo('Disconnected from: IP' + AContext.Binding.PeerIP + ' Port: ' + IntToStr(AContext.Binding.Port) + ' / ' +
    IntToStr(AContext.Binding.PeerPort));
end;

procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  s: string;
begin
  //  client 메시지 수신후 응답 전송
  s := AContext.Connection.IOHandler.ReadLn();
  if s <> '' then
  begin
    TMyNotify.AddTextToMemo('Client: ' + s);
    AContext.Connection.IOHandler.WriteLn('Got it! (' + s + ')');
    TMyNotify.AddTextToMemo('We say: ' + 'Got it! (' + s + ')');
  end;
end;



procedure TForm1.Button3Click(Sender: TObject);
begin
  Memo1.Lines.Add('We say: ' + Edit2.Text);
  IdTCPClient1.IOHandler.WriteLn(Edit2.Text);
  Edit2.SetFocus;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  Close;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Button2.Click;
  IdTCPServer1.Active := false;
end;

end.

 

실행 예시 화면

image.png

이 댓글 링크
다른 사이트에 공유하기

이 토의에 참여하세요

지금 바로 의견을 남길 수 있습니다. 그리고 나서 가입해도 됩니다. 이미 회원이라면, 지금 로그인하고 본인 계정으로 의견을 남기세요.

Guest
이 토픽(기고/질문)에 답하기

×   서식있는 텍스트로 붙여넣기.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   이전에 작성한 콘텐츠가 복원되었습니다..   편집창 비우기

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

중요한 정보

이용약관 개인정보보호정책 이용규칙 이 사이트가 더 잘 작동하기 위해 방문자의 컴퓨터에 쿠키가 배치됩니다. 쿠키 설정 변경에서 원하는 설정을 할 수 있습니다. 변경하지 않으면 쿠키를 허용하는 것으로 이해합니다.