[Delphi] 초간단 채팅 클라이언트 작성

Source : http://cafe.naver.com/codeway

Chapter 2

초간단 채팅 클라이언트 작성

본 강좌는 “델파이로 만드는 네트워킹 게임”을 목적으로 작성하던 것을 다시 수정 보안하여 만들어 가고 있는 것입니다.

네트워킹의 기본적인 기술 및 지식은 설명하지 않을 생각입니다. 이러한 기본 정보가 필요하신 분들은 네트워킹에 관한 인터넷 자료나 서적을 미리 한 번 읽어보시길 권장합니다.

우선은 채팅 프로그램을 작성하면서 델파이로 작성되는 네트워킹 프로그램의 기본적인 개념을 단계별로 설명하고, 추후 게임까지 연장해 보도록 하겠습니다.

http://cafe.naver.com/codeway 로 가시면 부족하지만 그 동안의 작업들을 보실 수 있습니다.

2004년 2월 25일, 류종택 드림.

본 강좌에서 사용되는 콤포넌트는 Indy 콤포넌트 입니다. http://www.nevrona.com/indy 로 가시면 해당 콤포넌트에 대한 상세한 정보를 얻으실 수 있습니다. 이 강좌에서는 인디 콤포넌트 중에서도 TCP/IP 통신용 콤포넌트를 중심으로 설명하게 됩니다.

l 강좌 대상 : 델파이로 네트워킹(소켓) 프로그래밍을 처음 해보시는 분

l 강좌 목적

– C/S (클라이언트/서버) 방식의 1:n 네트워킹 프로그램의 개념적 이해

– Indy 콤포넌트의 TCP/IP 콤포넌트의 기본적인 사용 방법 연습

프로퍼티 설정

clip_image002

[그림 2.1] 메인폼(TForm1)

1: object Form1: TForm1
2: Width = 580
3: Height = 340
4:
5: object Panel1: TPanel
6:   Align = alBottom
7:   BevelOuter = bvNone
8:
9: object edUserName: TEdit
10: Left = 8
11: Top = 8
12: Width = 121
13: Height = 21
14: Text = ”
15: end
16: object edMsg: TEdit
17: Left = 136
18: Top = 8
19: Width = 345
20: Height = 21
21: Text = ”
22: OnKeyPress = edMsgKeyPress
23: end
24: object Button1: TButton
25: Left = 494
26: Top = 8
27: Width = 75
28: Height = 25
29: Anchors = [akTop, akRight]
30: Caption = ‘Á¢¼Ó’
31: OnClick = Button1Click
32: end
33: end
34:
35: object moMsg: TMemo
36: Align = alClient
37: ReadOnly = True
38: end
39:
40: object IdTCPClient1: TIdTCPClient
41: Host = ‘127.0.0.1’
42: Port = 1234
43: end
44:
45: object IdAntiFreeze1: TIdAntiFreeze
46: end
47:
48: object Timer1: TTimer
49: Interval = 300
50: OnTimer = Timer1Timer
51: end
52:
53: end

전반적인 프로퍼티 설정 방법 및 순서는 동영상 자료를 참고하시기 바랍니다. (http://cafe.naver.com/codeway)

22: 라인에서 사용자가 대화 내용을 입력하고 엔터키를 치면 대화내용을 서버로 전송하기 위해 키가 눌려질 때 발생하는 이벤트를 사용하였습니다. 이벤트 핸들러에서는 눌러진 키가 엔터키일 경우에는 서버로 메시지를 전달하고 현재 대화내용은 다음 대화내용을 작성하기 위해 공백으로 바꿔버리도록 코딩하기로 하겠습니다.

31: 라인에서는 채팅을 하기 위해 서버에 접속하기 위한 버턴이 클릭되었을 때 실행될 이벤트를 사용하였습니다. 이후 버턴이 눌러지면 서버로 접속하도록 코딩하겠습니다.

37: 라인은 대화내용을 순서대로 화면에 표시할 TMemo 콤포넌트를 읽기전용으로 변경하는 것입니다.

40: 라인에서 내려놓은 TidTCPClient 콤포넌트는 TCP/IP 클라이언트용 컴포넌트 입니다. 서버로 접속하여 메시지를 전달하거나 수신할 수 있는 기능을 갖추고 있습니다.

41-42: 라인에서는 서버로 접속하기 위하여 서버의 주소와 포트 번호를 지정하였습니다. ‘127.0.0.1’은 자신의 컴퓨터로 접속할 때 사용하는 IP 주소입니다.

45: 라인에서 TidAntiFreeze는 인디 콤포넌트가 송수신을 할 때 사용자 인터페이스를 멈추게(얼도록)할 수가 있습니다. 즉, 채팅 클라이언트 프로그램이 잠시 “응답없음” 상태와 같이 정지된 상태가 되는 것을 말합니다. 해당 콤포넌트는 이러한 현상을 방지하여 줍니다. 사용법은 내려놓기만 하면 스스로 작동합니다.

48: 라인에서 서버로부터 메시지가 전달 되었는지 수시로 점검하기 위해서 TTimer 콤포넌트를 사용하였습니다.

49: 라인에서는 서버로부터 메시지가 전달 되었는지 점검하는 시간을 300ms (300/1000초) 간격으로 지정하였습니다.

50: 라인에서는 타이머가 지정된 시간마다 발생하는 OnTimer 이벤트를 이용하여 서버로부터 메시지가 전달되었는 지 확인하게 됩니다.

소스 분석

1: unit uClient;
2:
3: interface
4:
5: uses
6: Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
7: Dialogs, StdCtrls, ExtCtrls, IdAntiFreezeBase, IdAntiFreeze,
8: IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;
9:
10: type
11: TForm1 = class(TForm)
12: moMsg: TMemo;
13: Panel1: TPanel;
14: edUserName: TEdit;
15: edMsg: TEdit;
16: IdTCPClient1: TIdTCPClient;
17: IdAntiFreeze1: TIdAntiFreeze;
18: Button1: TButton;
19: Timer1: TTimer;
20: procedure Button1Click(Sender: TObject);
21: procedure Timer1Timer(Sender: TObject);
22: procedure edMsgKeyPress(Sender: TObject; var Key: Char);
23: private
24: { Private declarations }
25: public
26: { Public declarations }
27: end;
28:
29: var
30: Form1: TForm1;
31:
32: implementation
33:
34: {$R *.dfm}
35:
36: procedure TForm1.Button1Click(Sender: TObject);
37: begin
38: IdTCPClient1.Connect;
39: end;
40:
41: Function ReceiveText(IdTCPClient:TIdTCPClient):String;
42: Var
43: Data : Pointer;
44: DataSize : Integer;
45: ssData : TStringStream;
46: Begin
47: DataSize:= IdTCPClient.ReadFromStack(True, 5, False);
48: If DataSize = 0 then Begin
49: Result:= ”;
50: Exit;
51: End;
52:
53: GetMem(Data, DataSize);
54: ssData:= TStringStream.Create(”);
55: Try
56: IdTCPClient.ReadBuffer(Data^, DataSize);
57: ssData.Write(Data^, DataSize);
58: ssData.Position:= 0;
59: Result:= ssData.DataString;
60: Finally
61: FreeMem(Data);
62: ssData.Free;
63: End;
64: End;
65:
66: procedure TForm1.Timer1Timer(Sender: TObject);
67: Var
68: stText : String;
69: begin
70: If IdTCPClient1.Connected = False then Exit;
71:
72: stText:= ReceiveText(IdTCPClient1);
73: If stText <> ” then moMsg.Lines.Add(stText);
74: end;
75:
76: procedure TForm1.edMsgKeyPress(Sender: TObject; var Key: Char);
77: begin
78: If Key = #13 then Begin
79: Key:= #0;
80: IdTCPClient1.WriteLn(Format(‘%s> %s’, [edUserName.Text, edMsg.Text]));
81: edMsg.Text:= ”;
82: End;
83: end;
84:
85: end.

38: 라인은 서버로 접속하는 부분입니다. 이미 주소와 포트를 프로퍼티 설정 부분에서 지정해 주었기 때문에 우리는 단순히 Connect 메소드만 실행하는 것만으로도 충분합니다.

41-64: 라인은 TidTCPClient 콤포넌트의 ReadLn 메소드의 버그를 피하기 위해서 필자가 작성한 함수 입니다. 지금은 버그가 패치된 버전이 있으니 http://www.nevrona.com/indy에서 새로운 버전을 다운 받아 설치하시면 이 함수는 굳이 작성하지 않으셔도 됩니다. 이것저것 귀찮거나 헛갈리시는 분들은 우선 ReceiveText 함수를 사용하시기 바랍니다.

66-74: 라인은 주기적으로 서버로부터 메시지가 전송 되었는지 확인하고, 메시지가 수신되었으면 화면(TMemo)에 표시하는 부분입니다.

72: 라인은 버그가 패치된 인디를 설치하였을 경우에는 stText:= IdTCPClient1.ReadLn(”, 5); 로 변경하셔도 됩니다.

76-83: 라인은 사용자가 대화내용을 입력하고 엔터키를 입력할 때 서버로 메시지를 전송하는 부분입니다.

78: 라인에서는 눌러진 키값이 엔터키와 같은 지 비교합니다. 엔터키가 눌러지면 Key 변수는 #13 즉, 13번 아스키 문자가 입력됩니다.

79: 라인에서는 엔터키 일 때에는 키값을 아무것도 안눌러졌음으로 변경했습니다. 이는 TEdit 콤포넌트에서 엔터키를 치면 “팅”하는 소리가 나는 것을 방지하기 위해서 입니다. 대화내용을 전송할 때 마다 “팅”, “팅”하는 소리가 난다면 그다지 대화하고픈 분위기가 되지는 않을 테니까요 ^^

80: 라인에서는 입력된 메시지와 입력된 사용자 이름을 “이름> 대화내용”과 같은 방식으로 서버에 전송합니다. 이후 모든 클라이언트에 해당 형식으로 전송되어 화면에 나타나게 됩니다.

81: 라인에서는 입력창을 비워서 다음 대화내용을 입력 받을 수 있도록 준비합니다.

실행 및 테스트

clip_image004

[그림 2.2] 채팅 프로그램을 실행한 화면

서버를 실행한 후 클라이언트 프로그램 두 개를 띄우고 각각 접속 버턴을 누르시기 바랍니다. 이후 각각의 클라이언트의 왼쪽에 있는 입력창에 자신의 대화명을 각각 입력하고 오른쪽 옆에 있는 메시지 입력창에 대화내용을 입력하고 엔터키를 치면 위의 화면처럼 서로 대화를 나눌 수 있게 됩니다.

원거리에 있는 사용자들 끼리 사용하고자 할 때에는 서버의 IP 주소를 다시 입력하시고 컴파일 한 후에 사용하시기 바랍니다.

끝으로

다음에는 1:1 메시지 전달, 귓속말 그리고 로그인 처리 등과 같은 기능을 하나씩 추가해 나가며 강좌를 진행해 나가도록 하겠습니다.

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중

%d 블로거가 이것을 좋아합니다: