본문 바로가기
Delphi Tip/통신

델파이 소켓(통신) 프로그램

by MonoSoft 2023. 10. 23.
728x90
반응형

델파이 소켓 프로그램

728x90

 

 

델파이 소켓(통신) 프로그램

 

 

송수신 방식

1. 심플렉스 (Simplex)

: 한 지점에서 다른 지점으로만 보내는 방식

2. 하프 – 듀플렉스 (Half - Duplex)

: 동시에 양방향으로 통신할 수는 없고 한 지점에서

다른 지점으로 보낼 때는 받는 지점에서는 받기만 할 수 있고

보낼 수는 없는 방식

3. 풀 – 듀플렉스 (Full - Duplex)

: 양방향 통신이 가능한 방식

 

데이터 전송에 필요한 요소

1. Ip

2. Port

3. Packet

 

네트워크 통신 유형

1. TCP (Transmission Control Protocol)

: 목적지와 일단 접속을 이룬 다음에 데이터를 전송하는 연결 지향 프로토콜

2. UDP (User Datagram Protocol)

: 사전 접속을 이루는 작업없이 처음부터 데이터와 목적지

주소만을 패킷에 실어 데이터를 주고 받는 비연결성 프로토콜

 

소켓(Socket)

같은 컴퓨터 혹은 네트워크로 연결된 컴퓨터의 두 프로그램 프로세스들 간의 데이터 교환을 위한 약정

 

- 연결 지향의 통신 절차 : BSD Sockets

 

소켓이 사용하는 구조체

struct sockaddr {

  unsigned short sa_family;

  char sa_data[14];

};

 

소켓이 지원하는 여러 개의 프로토콜에서 사용될 수 있도록

각각의 프로토콜에 맞게 다음과 같이 재선언되어 있다.

 

struct in_addr {

  u_long s_addr;

};

 

struct sockaddr_in {

  short sin_family;                // 사용하고자 하는 프로토콜의 종류 지정

  short sin_port;                   // 포트번호(프로세스를 식별해주는) 지정

  struct   in_addr sin_addr; // 호스트의 논리적인 주소(IP 어드레스) 지정

  char sin_zero[8];

};

 

socket()

파일 디스트럽터와 소켓 디스트럽터를 할당받음.

 

bind()

socket()에 의해 생성된 소켓 디스트럽트를 통해 프로토콜 레벨에게 자신의 주소와 포트 번호를 연결시킴.

 

connect()

목적지 Ip주소가 지정되어 있는 구조체(접속하고자 하는 서버의 정보)를 인자로 받아

소켓 디스트럽트를 통해 접속 요청

 

listen()

서버가 클라이언트로부터 들어오는 접속 요청을 동시에

받아들일 수 있는 접속 요청 수를 지정.

클라이언트의 접속이 오면 fork() 함수를 수행하여 동시에 서비스를 처리하는

서버 프로세스의 수를 제한함

 

accept()

클라이언트로부터 요청을 기다리다가 요청을 실제적으로 받아들이는 함수.

병행 서버의 경우 접속이 들어오면, fork()를 수행하여 자식 프로세스에게

이의 처리를 맡기고 자신은 또다른 접속을 기다릴 수 있다.

 

close()

대개 클라이언트가 서버에게 접속 해제 요청을 보낼 때 사용하며

네트워크 입출력에서는 개방된 소켓에 대한 작업을 끝낼 때는 반드시 close()를 사용하여야 한다.

 

윈속(Winsock: Windows Sockets)

윈속은 표준 open network API 이다.

 

Windows 계열의 모든 플랫폼에서 TCP/IP를 위한 표준 프로그래밍 인터페이스이다.

즉, Windows 계열에서 TCP/IP를 이용할 수 있도록 해주는 프로그램을 말한다.

 

Windows 계열의 플랫폼에서

BSD(Berkeley Software Distribution ; Berkeley Software Design) Socket의

Unix 소스 코드가 작동하도록 포팅함으로써 애플리케이션 개발을 쉽게 해준다.

 

하지만 윈속은 BSD Sockets와 100% 호환되지는 않는다.

 

다양한 윈속 프로그램이 존재한다.

트럼펫 윈속은 독립적인 윈속 버전으로 잘 알려져 있다.

 

윈속 프로그램은 DLL형태로 존재하는데

아래 그림을 보면 그 동작 원리를 알 수 있다.

 

 

윈속2(Winsock2: Windows 2 Sockets) 

윈속2 또한 표준 애플리케이션 인터페이스이며, 윈속의 32비트 버전이다.

 

-윈속2는 윈속에 비해 몇가지 장점이 있다

1. TCP/IP 이외에도 IPX/SPX, ISDN, 무선 프로토콜,

그리고 OSI 등을 포함하는 다양한 프로토콜을 지원한다.

 

2. 애플리케이션은 멀티캐스팅과 윈속1.1에서 지원되지 않는

다른 프로토콜 서비스들을 요청할 수 있다.

 

3. 다중 이름 공간을 액세스할 수 있다.

 

4. 비용에 따라 서비스를 선택할 수 있는 애플리케이션을 제공한다.

 

 

다음은 윈속2의 동작 원리이다.

 

 

델파이에서의 윈속 구조

델파이에서 윈속에 관련된 사항을 알려면 WinSock.pas를 열어보면 된다.

 

WinSock API가 모두 매핑(mapping)이 되어있는 걸 볼 수 있다.

 

타입이나 구조체, 상수가 선언되어져 있고

그 외의 함수들은 모두 winsock.dll에 링크되어져 있다.

 

위에서 언급한 사항들이 어떻게 매핑이 되는가 보자.

 

다음은 WinSock.pas 내용 중 일부이다.

 

PInAddr = ^TInAddr;

 

{$EXTERNALSYM in_addr}

 

in_addr = record

case integer of

  0: (S_un_b: SunB);

  1: (S_un_w: SunW);

  2: (S_addr: u_long);

end;

 

TInAddr = in_addr;

 

PSockAddrIn = ^TSockAddrIn;

 

{$EXTERNALSYM sockaddr_in}

 

sockaddr_in = record

case Integer of

0: (sin_family: u_short;

     sin_port: u_short;

     sin_addr: TInAddr;

     sin_zero: array[0..7] of Char);

1: (sa_family: u_short;

     sa_data: array[0..13] of Char)

end;

 

TSockAddrIn = sockaddr_in;

function accept; external winsocket name 'accept';

function bind; external winsocket name 'bind';

function closesocket; external winsocket name 'closesocket';

function connect; external winsocket name 'connect';

function getpeername; external winsocket name 'getpeername';

function getsockname; external winsocket name 'getsockname';

function getsockopt; external winsocket name 'getsockopt';

function htonl; external winsocket name 'htonl';

function htons; external winsocket name 'htons';

function inet_addr; external winsocket name 'inet_addr';

function inet_ntoa; external winsocket name 'inet_ntoa';

function ioctlsocket; external winsocket name 'ioctlsocket';

function listen; external winsocket name 'listen';

function ntohl; external winsocket name 'ntohl';

function ntohs; external winsocket name 'ntohs';

function recv; external winsocket name 'recv';

function recvfrom; external winsocket name 'recvfrom';

function select; external winsocket name 'select';

function send; external winsocket name 'send';

function sendto; external winsocket name 'sendto';

function setsockopt; external winsocket name 'setsockopt';

function shutdown; external winsocket name 'shutdown';

function socket; external winsocket name 'socket';

 

윈속을 사용할 수 있도록 Winsock.pas에 모두 정의 되어있으므로

소켓에 대한 개념을 잘 이해한다면 컴포넌트를 사용하지 않고도 프로그램을 짤 수 있겠다.

 

하지만 특별한 경우가 아니라면 여러가지 소켓 관련 컴포넌트를 이용하여

빠르고 안전하게 프로그래밍을 하도록 하자.

 

소켓 컴포넌트

소켓 컴포넌트에 관련해서는 SockComp.pas를 참조할 수 있다.

 

 

아래의 코드에 유념할 필요가 있다

ESocketError = class(Exception);

TCustomWinSocket = class;

TCustomSocket = class;

TServerAcceptThread = class;

TServerClientThread = class;

TServerWinSocket = class;

TServerClientWinSocket = class;

TServerType = (stNonBlocking, stThreadBlocking);

TClientType = (ctNonBlocking, ctBlocking);

TAsyncStyle = (asRead, asWrite, asOOB, asAccept, asConnect, asClose);

TAsyncStyles = set of TAsyncStyle;

TSocketEvent = (seLookup, seConnecting, seConnect, seDisconnect, seListen, seAccept, seWrite, seRead); TLookupState = (lsIdle, lsLookupAddress, lsLookupService);

TErrorEvent = (eeGeneral, eeSend, eeReceive, eeConnect, eeDisconnect, eeAccept);

TSocketEventEvent = procedure (Sender: TObject; Socket: TCustomWinSocket; SocketEvent: TSocketEvent) of object; TSocketErrorEvent = procedure (Sender: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer) of object;

TGetSocketEvent = procedure (Sender: TObject; Socket: TSocket; var ClientSocket: TServerClientWinSocket) of object; TGetThreadEvent = procedure (Sender: TObject; ClientSocket: TServerClientWinSocket; var SocketThread: TServerClientThread) of object;

TSocketNotifyEvent = procedure (Sender: TObject; Socket: TCustomWinSocket) of object;

 

소켓 컴포넌트에서 발생하는 이벤트는 위의 T*****Event 메소드포인터에서 처리된다.

 

소켓 컴포넌트를 사용하기 위해서 “Internet” 팔레트 안의

ClientSocket과 ServerSocket을 사용할 수 있다.

 

ClientSocket 상속 구조

TObject > TPersistent > TComponent > TAbstractSocket > TCustomSocket >TClientSocket

 

ServerSocket 상속 구조

TObject > TPersistent > TComponent > TAbstractSocket > TCustomSocket >

TCustomServerSocket > TServerSocket

 

TCustomSocket은 위의 구조에서도 보듯이 TComponent의 자손으로

소켓 클래스를 담기 위한 그릇으로써의 클래스이다.

 

실제 소켓의 핸들이나 윈속 API를 구현한 클래스는 TCustomWinSocket 이다.

 

 

좀 더 자세한 클래스 구조를 확인하기 위해서는

SockComp.pas 을 열어보기 바란다.

 

우리는 위에서 Server / Client 간의 연결 지향의

통신 절차에 대해서 살펴보았다.

 

델파이에서는 어떻게 진행되는 가를 살펴보자.

클라이언트는 TClientSocket이 TClientWinSocket의 Connect프로시저로 접속을 한다.

 

서버에서는 TServerSocket이 TServerWinSocket에서 Listen프로시저에 의해

계속 Listenning을 하다가 클라이언트와 접속이 되면

TServerClientSocket에 연결시켜주게 되며 자신은 다시 Listenning을 하게 된다.

 

이때 통신은 블로킹(blocking: 동기화 모드)과

넌블로킹(non-blocking: 비동기화 모드)으로 나눌 수가 있는데

이에 대한 설명은 다음 기회에 다루도록 하겠다.

 

델파이 소켓 프로그램시 기본적으로 넌블로킹이 적용된다.

간단히 설명하자면 넌블로킹은 소켓의 자료 전송이

윈도우 소켓 메시지가 발생할 때마다 비동기적으로 전달되며

블로킹은 동기화된 전송을 하게 된다.

 

넌블로킹에서는 TCustomWinSocket이 TCustomSocket의

이벤트를 호출하므로 On이벤트 발생시 ReadBuffer/WriteBuffer 루틴을

작성함으로써 비교적 쉽게 프로그래밍을 할 수 있다.

 

하지만 블로킹에서는 On이벤트에서 처리할 수 없기 때문에

TWinSocketStream을 통해 자료를 주고 받게 된다.

 

이번 세미나에서는 소켓 네트워크 프로그래밍을 위한

기본적인 개념과 원리에 대해 언급을 했다.

 

아주 간단하게나마 기본 구조를 이해함으로써

응용 프로그램을 만드는 데 있어서 많은 도움이 되리라는 생각을 한다.

 

728x90
반응형

댓글