Network Socket
네트워크 소켓(Network Socket)은 컴퓨터 네트워크에서 노드 내부의 데이터 송수신을 위한 내부 엔드포인트이다. 소켓은 네트워킹 소프트웨어(프로토콜 스택)에서 이 엔드포인트를 표현하는 방식으로, 통신 프로토콜, 목적지, 상태 등을 나열하는 테이블의 항목과 같은 형태로 존재하며, 일종의 시스템 리소스이다.
소켓 프로그래밍은 TCP/IP 네트워크의 통신 기반이 되는 근본적인 기술이다. 소켓은 다른 소켓과 데이터를 주고받기 위한 양방향 통신 엔드포인트를 제공한다. 소켓 연결은 일반적으로 로컬 영역 네트워크(LAN)나 인터넷을 통해 두 개의 서로 다른 컴퓨터 간에 실행되지만, 단일 컴퓨터에서 프로세스 간 통신(IPC)에도 사용될 수 있다.
소켓은 응용 프로그램과 네트워크 프로토콜 사이의 인터페이스 역할을 하며, 응용 프로그램이 네트워크 통신을 구현할 수 있게 해주는 프로그래밍 API를 제공한다. 소켓을 통해 개발자는 네트워크의 하위 계층 세부 사항을 걱정하지 않고 TCP나 UDP와 같은 전송 프로토콜을 사용하여 데이터를 교환할 수 있다.
네트워크 소켓은 소켓 주소로 식별되며, 이는 일반적으로 IP 주소와 포트 번호의 조합이다. 이 조합을 통해 네트워크에서 고유한 통신 엔드포인트를 정의할 수 있다. 클라이언트-서버 모델에서 서버는 특정 IP 주소와 포트에서 들어오는 연결을 수신하기 위해 소켓을 생성하고, 클라이언트는 서버의 소켓 주소를 사용하여 연결을 시도한다.
Socket Programming
소켓 프로그래밍은 클라이언트-서버 아키텍처를 기반으로 하며, 이 구조는 현대 네트워크 응용 프로그램의 기본 패러다임이 되었다. 이 아키텍처에서 소켓 서버와 소켓 클라이언트는 각각 고유한 역할을 수행한다.
소켓 서버는 다른 프로그램이 연결하기 위해 대기하는 프로그램이다. 웹 서버, 이메일 서버 등이 대표적인 예시이다. 소켓 서버는 특정 IP 주소와 포트에서 수신 연결을 대기하며, 연결 요청이 오면 클라이언트와의 통신을 처리한다.
소켓 클라이언트는 다른 프로그램에 연결하도록 설계된 프로그램이다. 웹 브라우저, 휴대폰의 이메일 앱, 모바일 장치의 대부분의 인터넷 게임 등이 여기에 해당한다. 클라이언트는 서버의 IP 주소와 포트 번호를 사용하여 서버에 연결하고 통신을 시작한다.
버클리 소켓 API(Berkeley Socket API)는 인터넷 소켓과 유닉스 도메인 소켓을 위한 응용 프로그램 프로그래밍 인터페이스로, 프로세스 간 통신(IPC)에 사용된다. 이는 일반적으로 연결 가능한 모듈의 라이브러리로 구현되며, 1983년에 출시된 4.2 BSD 유닉스 운영 체제에서 처음 등장했다. 버클리 소켓은 거의 변경 없이 발전하여 사실상의 표준에서 POSIX 사양의 구성 요소가 되었다.
버클리 소켓 API는 다음과 같은 주요 함수들을 제공한다:
- socket()은 특정 유형의 새 소켓을 생성하고, 정수로 식별하며, 시스템 리소스를 할당한다.
- bind()는 주로 서버 측에서 사용되며, 소켓을 소켓 주소 구조(즉, 지정된 로컬 IP 주소 및 포트 번호)와 연결한다.
- listen()은 서버 측에서 사용되며, 바인딩된 TCP 소켓이 수신 대기 상태로 전환되도록 한다.
- connect()는 클라이언트 측에서 사용되며, 소켓에 무료 로컬 포트 번호를 할당한다. TCP 소켓의 경우, 원격 서버와의 새로운 TCP 연결을 설정하려는 시도를 한다.
- accept()는 서버 측에서 사용된다. 원격 클라이언트로부터 새 TCP 연결을 생성하려는 수신된 시도를 수락하고, 이 연결의 소켓 주소 쌍과 연결된 새 소켓을 생성한다.
- send(), recv(), sendto(), recvfrom()은 데이터를 송수신하는 데 사용된다. 표준 함수인 write()와 read()도 사용할 수 있다.
- close()는 시스템이 소켓에 할당된 리소스를 해제하도록 한다. TCP의 경우 연결이 종료된다.
- gethostbyname()과 gethostbyaddr()는 호스트 이름과 주소를 확인하는 데 사용된다. IPv4만 지원한다.
- select()는 제공된 소켓 목록 중 하나 이상이 읽기 준비, 쓰기 준비 또는 오류가 있는지 기다리며 일시 중단하는 데 사용된다.
- poll()은 소켓 집합에서 소켓 상태를 확인하는 데 사용된다. 이 집합은 소켓이 쓰기, 읽기가 가능한지 또는 오류가 발생했는지 테스트할 수 있다.
- getsockopt()는 지정된 소켓에 대한 특정 소켓 옵션의 현재 값을 검색하는 데 사용된다.
- setsockopt()는 지정된 소켓에 대한 특정 소켓 옵션을 설정하는 데 사용된다.
Server - Client
Python으로 구현된 TCP 에코 서버 코드는 다음과 같은 과정을 수행한다:
- 서버는 로컬호스트(127.0.0.1)의 포트 65456에서 TCP 소켓을 생성하고 바인딩한다.
- listen() 메서드로 연결 대기 상태가 되며, accept() 메서드로 클라이언트의 연결 요청을 수락한다.
- 클라이언트가 연결되면, 클라이언트의 IP 주소와 포트 번호를 출력한다.
- 무한 루프에서 클라이언트로부터 데이터를 수신(recv)하고, 동일한 데이터를 다시 클라이언트에게 전송(sendall)하는 에코 기능을 수행한다.
- 클라이언트가 'quit' 메시지를 보내면 통신을 종료한다.
TCP 에코 클라이언트 코드는 다음과 같은 과정을 수행한다:
- 클라이언트는 서버와 동일한 로컬호스트 주소와 포트를 사용하여 소켓을 생성하고 서버에 연결한다.
- 무한 루프에서 사용자로부터 입력을 받아 서버에 전송하고, 서버로부터 응답을 수신하여 출력한다.
- 사용자가 'quit'을 입력하면 통신을 종료한다.
Socket API Functions
소켓 API 함수들은 네트워크 프로그래밍의 기초를 형성하며, 특히 socket(), bind(), listen(), accept(), connect() 함수들은 클라이언트-서버 아키텍처의 핵심 구성 요소이다.
socket() 함수는 통신을 위한 엔드포인트를 생성하고 소켓에 대한 파일 디스크립터를 반환한다. 오류가 발생하면 -1을 반환하고, 그렇지 않으면 새로 할당된 디스크립터를 나타내는 정수를 반환한다. 이 함수는 세 가지 인자를 사용한다:
- domain: 생성된 소켓의 프로토콜 패밀리를 지정한다.
- AF_INET: 네트워크 프로토콜 IPv4(IPv4 전용)
- AF_INET6: IPv6(일부 경우 IPv4와 하위 호환)
- AF_UNIX: 로컬 소켓(특수 파일 시스템 노드 사용)
- type: 소켓 유형을 지정한다.
- SOCK_STREAM(TCP): 신뢰성 있는 스트림 지향 서비스 또는 스트림 소켓
- SOCK_DGRAM(UDP): 데이터그램 서비스 또는 데이터그램 소켓
- SOCK_SEQPACKET: 신뢰성 있는, 순서가 보장된 패킷 서비스
- SOCK_RAW: 네트워크 계층 위의 원시 프로토콜
- protocol: 사용할 실제 전송 프로토콜을 지정한다. 가장 일반적인 것은 IPPROTO_TCP, IPPROTO_SCTP, IPPROTO_UDP, IPPROTO_DCCP이다. 이 프로토콜들은 파일 netinet/in.h에 지정되어 있다. 값 0을 사용하여 선택된 도메인과 유형에서 기본 프로토콜을 선택할 수 있다.
bind() 함수는 소켓을 주소와 연결한다. socket()으로 소켓이 생성될 때, 그것은 단지 프로토콜 패밀리만 부여받을 뿐 주소는 할당되지 않는다. 소켓이 다른 호스트로부터 연결을 수락하기 전에 이 연결 작업이 수행되어야 한다. bind()는 성공 시 0을 반환하고, 오류 발생 시 -1을 반환한다. 이 함수는 세 가지 인자를 가진다:
- sockfd: 소켓을 나타내는 디스크립터
- my_addr: 바인딩할 주소를 나타내는 sockaddr 구조체에 대한 포인터
- addrlen: sockaddr 구조체의 크기를 지정하는 socklen_t 유형의 필드
listen() 함수는 소켓이 주소와 연결된 후, 들어오는 연결을 준비한다. 그러나 이는 스트림 지향(연결 지향) 데이터 모드, 즉 소켓 유형(SOCK_STREAM, SOCK_SEQPACKET)에서만 필요하다. listen()은 두 가지 인자를 필요로 한다:
- sockfd: 유효한 소켓 디스크립터
- backlog: 한 번에 대기열에 추가될 수 있는 보류 중인 연결 수를 나타내는 정수. 운영 체제는 일반적으로 이 값에 제한을 둔다.
연결이 수락되면, 그것은 대기열에서 제거된다. 성공 시 0이 반환되고, 오류 발생 시 -1이 반환된다.
accept() 함수는 애플리케이션이 다른 호스트로부터 스트림 지향 연결을 수신하고 있을 때, 그러한 이벤트가 통지되면(cf. select() 함수) accept() 함수를 사용하여 연결을 초기화해야 한다. 이 함수는 각 연결에 대해 새 소켓을 생성하고 연결을 대기 목록에서 제거한다. 이 함수는 다음과 같은 인자를 가진다:
- sockfd: 연결이 대기 중인 리스닝 소켓의 디스크립터
- cliaddr: 클라이언트의 주소 정보를 받기 위한 sockaddr 구조체에 대한 포인터
- addrlen: accept()에 전달된 클라이언트 주소 구조체의 크기를 지정하는 socklen_t 위치에 대한 포인터. accept()가 반환될 때, 이 위치에는 구조체의 크기(바이트)가 포함된다.
accept()는 수락된 연결에 대한 새 소켓 디스크립터를 반환하거나, 오류 발생 시 -1 값을 반환한다. 원격 호스트와의 모든 추가 통신은 이제 이 새 소켓을 통해 이루어진다. 데이터그램 소켓은 수신자가 즉시 리스닝 소켓을 사용하여 요청에 응답할 수 있기 때문에 accept()에 의한 처리가 필요하지 않다.
connect() 함수는 파일 디스크립터로 식별되는 소켓을 통해 주소로 식별되는 특정 원격 호스트에 직접 통신 링크를 설정한다. 연결 지향 프로토콜을 사용할 때, 이는 연결을 설정한다. 특정 유형의 프로토콜, 특히 사용자 데이터그램 프로토콜(UDP)은 연결이 없다. 연결 없는 프로토콜과 함께 사용될 때, connect는 데이터를 보내고 받기 위한 원격 주소를 정의하여 send와 recv와 같은 함수를 사용할 수 있게 한다. 이러한 경우, connect 함수는 다른 소스로부터의 데이터그램 수신을 방지한다.
connect()는 오류 코드를 나타내는 정수를 반환한다: 0은 성공을 나타내고, -1은 오류를 나타낸다. 역사적으로, BSD 파생 시스템에서는 connect 호출이 실패할 경우 소켓 디스크립터의 상태가 정의되지 않았다(단일 유닉스 사양에 지정된 대로). 따라서, 이식 가능한 애플리케이션은 connect() 호출이 실패할 경우 소켓 디스크립터를 즉시 닫고 socket()으로 새 디스크립터를 얻어야 한다.
Enhanced Client-Server
개선된 TCP 에코 서버 코드는 다음과 같은 특징을 갖는다:
- 구조화된 설계: 코드는 main() 함수로 캡슐화되어 있고 if __name__ == "__main__": 구문을 사용하여 모듈로 가져올 때와 직접 실행할 때의 동작을 구분한다.
- 예외 처리: bind() 메서드 호출 시 발생할 수 있는 예외를 try-except 블록으로 처리하고 있다. 바인딩 실패 시 적절한 오류 메시지를 출력하고 소켓을 닫은 후 프로그램을 종료한다.
- 반환 값 확인: bind()와 listen() 메서드의 반환 값을 확인하여 실패 시 프로그램을 적절히 종료한다.
- 리소스 관리: Python의 with 문을 사용하여 소켓 리소스가 자동으로 해제되도록 보장한다.
- 클라이언트 정보 출력: 연결된 클라이언트의 IP 주소와 포트 번호를 출력하여 디버깅 및 모니터링에 도움을 준다.
개선된 TCP 에코 클라이언트 코드는 다음과 같은 특징을 갖는다:
- 구조화된 설계: 서버와 마찬가지로 main() 함수와 모듈 실행 구분을 포함하고 있다.
- 예외 처리: connect() 메서드 호출 시 발생할 수 있는 예외를 처리하고, 연결 실패 시 적절한 오류 메시지를 출력한다.
- 사용자 상호작용: 사용자로부터 입력을 받아 서버에 전송하고, 서버로부터 받은 응답을 출력한다.
- 종료 조건: 사용자가 'quit' 메시지를 입력하면 통신을 종료한다.
Socket Programming (1:N)
socketserver는 Python에서 소켓 기반 네트워크 서버 개발을 지원하는 내장 모듈이다. 이 모듈은 다음 네 가지 유형의 서버 클래스를 제공한다:
- TCPServer: 인터넷 TCP 프로토콜을 사용하여 클라이언트와 서버 간 연속적인 데이터 스트림을 제공한다.
- UDPServer: 인터넷 UDP 프로토콜을 사용한다.
- UnixStreamServer: Unix 도메인 소켓 스트림을 사용한다.
- UnixDatagramServer: Unix 도메인 소켓 데이터그램을 사용한다.
이 중 TCPServer 클래스가 가장 일반적으로 사용된다.
위 코드는 다음과 같은 단계로 socketserver.TCPServer를 사용하여 에코 서버를 구현하고 있다:
- 요청 핸들러 클래스 생성하기: socketserver.BaseRequestHandler 클래스를 상속하고 handle() 메서드를 오버라이드하여 클라이언트 요청을 처리하는 MyTCPSocketHandler 클래스를 정의한다.
- 서버 인스턴스 생성하기: socketserver.TCPServer 클래스의 인스턴스를 생성하고, 서버 주소(호스트, 포트)와 요청 핸들러 클래스(MyTCPSocketHandler)를 전달한다.
- 서버 활성화하기: serve_forever() 메서드를 호출하여 서버를 활성화하고, 클라이언트 연결을 무한정 수신 대기한다.
handle() 메서드 내부에서는 기본 에코 서버의 기능을 구현하고 있다. 클라이언트로부터 데이터를 수신하고(self.request.recv), 동일한 데이터를 다시 클라이언트에게 전송한다(self.request.sendall). 클라이언트가 'quit' 메시지를 보내면 처리를 종료한다.
기본적인 socketserver.TCPServer는 한 번에 하나의 클라이언트만 처리할 수 있다는 중요한 제한사항이 있다. 각 요청은 다음 요청을 시작하기 전에 완료되어야 한다. 이는 각 요청이 완료하는 데 시간이 오래 걸리는 경우, 특히 계산량이 많거나 클라이언트가 처리하는 데 시간이 오래 걸리는 대량의 데이터를 반환하는 경우에 적합하지 않다.
이 문제를 해결하기 위한 방법은 각 요청을 처리하기 위한 별도의 프로세스나 스레드를 생성하는 것이다. Python socketserver 모듈은 이를 위해 두 가지 mixin 클래스를 제공한다:
- ForkingMixIn 사용하기: 각 클라이언트 요청에 대해 별도의 프로세스를 생성한다.
- ThreadingMixIn 활용하기: 각 클라이언트 요청에 대해 별도의 스레드를 생성한다.
이러한 mixin 클래스를 활용하면 비동기적 동작을 지원하여 여러 클라이언트를 동시에 처리할 수 있는 서버를 구현할 수 있다.
Asynchronous TCP socketserver
소켓 프로그래밍에서 동기식 처리와 비동기식 처리는 네트워크 연결 처리 방식에 있어 중요한 차이점을 가진다. 동기식 처리는 진행 중인 작업이 있으면, 다음 작업은 현재 진행 작업 종료 후 처리하는 방식으로, 일반적으로 'blocking 처리'라고 한다. 반면 비동기식 처리는 진행 중인 작업이 있어도, 다음 작업이 기다리지 않고 바로 실행되는 방식으로, 'non-blocking 처리'라고 한다.
Multi-Thread/Process는 쉽게 이해하자면 "일꾼이 되는 프로그램 갯수를 증가"시키는 방법이다. Multi-Process와 Multi-Thread가 일반적으로 사용된다. Multi-Process는 독립적인 프로그램을 실행하는 방식으로, 주로 fork() 함수를 통해 실행된다. Multi-Thread는 데이터를 공유하는 일꾼을 추가하는 방식으로, 이 일꾼을 Thread라고 칭하며, Process보다 자원 요구가 적다.


비동기식 TCP socketserver 개발은 다음 단계로 진행할 수 있다:
[단계 1] socketserver의 multi-thread 버전 생성하기
각 유형의 서버의 Forking 및 threading 버전은 이러한 mix-in 클래스를 사용하여 생성할 수 있다. mix-in 클래스는 socketserver에 정의된 메서드를 재정의하므로 먼저 와야 한다. 다양한 속성을 설정하면 기본 서버 메커니즘의 동작도 변경된다.
[단계 2] socketserver의 RequestHandler 수정하기
서비스를 구현하려면 BaseRequestHandler에서 클래스를 파생하고 handle() 메서드를 재정의해야 한다. 그런 다음 서버 클래스 중 하나와 요청 핸들러 클래스를 결합하여 서비스의 다양한 버전을 실행할 수 있다. 요청 핸들러 클래스는 데이터그램 또는 스트림 서비스에 따라 달라야 한다. 이는 StreamRequestHandler 또는 DatagramRequestHandler와 같은 핸들러 하위 클래스를 사용하여 숨길 수 있다.
[단계 3] MainThread 설정 및 실행하기
스레드 연결 동작을 위해 ThreadingMixIn에서 상속할 때 갑작스러운 종료 시 스레드가 어떻게 동작하기를 원하는지 명시적으로 선언해야 한다. ThreadingMixIn 클래스는 서버가 스레드 종료를 기다려야 하는지 여부를 나타내는 속성인 daemon_threads를 정의한다. 스레드가 자율적으로 동작하기를 원한다면 이 플래그를 명시적으로 설정해야 한다. 기본값은 False로, ThreadingMixIn에 의해 생성된 모든 스레드가 종료될 때까지 Python이 종료되지 않음을 의미한다.
threading.Thread(target=server.serve_forever)는 스레드의 활동을 표현하는 생성자로, 항상 키워드 인수와 함께 호출해야 한다. target은 run() 메서드에 의해 호출될 호출 가능한 객체이다. server_thread.start()는 스레드의 활동을 시작하고, threading.active_count()는 현재 살아있는 Thread 객체의 수를 반환한다. server_thread.run()은 스레드의 활동을 나타내는 메서드로, 하위 클래스에서 이 메서드를 재정의할 수 있다. 표준 run() 메서드는 객체 생성자에 target 인수로 전달된 호출 가능한 객체를 호출한다.
비동기식 TCP Chatting 서비스 개발
비동기식 TCP socketserver를 기반으로 채팅을 위한 간단한 형태의 서버와 클라이언트를 개발할 수 있다. 이러한 채팅 서비스는 다중 클라이언트가 동시에 메시지를 주고받을 수 있는 환경을 제공한다.
서버 변경 내용(소스코드의 {CHAT} 부분)에서는 모든 클라이언트의 소켓 연결 정보를 저장해두고(등록 및 삭제), 특정 클라이언트가 전송한 메시지를 모든 클라이언트들에 전달하는 기능을 구현해야 한다. 클라이언트 변경 내용(소스코드의 {CHAT} 부분)에서는 Thread를 사용하여 전송과 수신을 비동기적으로 분리하고, 수신 Thread를 통해 서버로부터의 전송에 항상 준비하는 방식으로 구현한다.


위 코드는 클라이언트 측 구현을 보여준다. 이 클라이언트는 다음과 같은 주요 특징을 가진다:
- 별도의 수신 핸들러(recvHandler)를 생성하여 서버로부터 데이터를 비동기적으로 수신한다.
- 클라이언트 스레드를 생성하고 daemon 속성을 True로 설정하여 메인 스레드가 종료될 때 함께 종료되도록 한다.
- 메인 스레드에서는 사용자 입력을 받아 서버로 전송하는 역할을 담당한다.


위 코드는 서버 측 구현으로 다음과 같은 주요 특징을 가진다:
- 모든 클라이언트의 소켓 정보를 저장하기 위한 전역 리스트(group_queue)를 생성한다.
- ThreadedTCPRequestHandler 클래스에서 handle 메서드를 재정의하여 클라이언트와의 통신을 처리한다.
- 새로운 클라이언트 연결 정보를 group_queue에 등록하고, 연결이 종료될 때 제거한다.
- 클라이언트로부터 메시지를 수신하면 모든 클라이언트에게 전달(브로드캐스트)한다.
- ThreadedTCPServer 클래스를 정의하여 ThreadingMixIn과 TCPServer를 결합한다.
- 서버 스레드를 생성하고 daemon 속성을 설정하여 메인 스레드 종료 시 함께 종료되도록 한다.
- 서버 종료는 모든 클라이언트 연결이 끊어진 상태에서 'quit' 입력 시 이루어지도록 구현된다.
이러한 구현을 통해 여러 클라이언트가 동시에 채팅에 참여할 수 있는 간단한 채팅 서비스를 개발할 수 있다. 사용자들은 메시지를 입력하면 해당 메시지가 모든 참여자에게 전달되고, 다른 사용자의 메시지를 실시간으로 수신할 수 있다.
UDP Echo
UDP(User Datagram Protocol)는 TCP와 달리 연결 없는(connection-less) 통신 방식을 사용하여, 연결 설정(connect) 과정 없이 데이터를 교환한다.
위 코드는 UDP 클라이언트 구현을 보여준다. 이 클라이언트는 다음과 같은 특징을 가진다:
- socket.SOCK_DGRAM을 사용하여 UDP 소켓을 생성한다.
- 비동기 수신을 위한 별도의 스레드(recvHandler)를 구현한다.
- 메인 스레드에서는 사용자 입력을 받아 sendto() 메서드로 서버에 데이터를 전송한다.
- sendto() 메서드는 데이터와 함께 목적지 주소(HOST, PORT)를 명시적으로 제공해야 한다.
- clientThread.daemon = True 설정으로 메인 스레드 종료 시 수신 스레드도 함께 종료되도록 한다.
위 코드는 UDP 서버 구현을 보여준다. 이 서버는 다음과 같은 특징을 가진다:
- socketserver.UDPServer 클래스를 사용하여 UDP 서버를 구현한다.
- TCP 핸들러와 유사하게 작동하지만, TCP와 달리 self.request는 데이터와 클라이언트 소켓의 쌍으로 구성된다.
- 연결이 없기 때문에 데이터를 다시 보낼 때 sendto() 메서드를 사용하고 클라이언트 주소를 명시적으로 제공해야 한다.
- handle() 메서드에서 RecvData = self.request[0].strip()을 통해 받은 데이터를 추출하고, RecvSocket = self.request[1]을 통해 소켓을 추출한다.
- RecvSocket.sendto(RecvData, self.client_address)를 사용하여 동일한: 데이터를 클라이언트에게 다시 전송한다.
UDP Echo 서비스는 TCP Echo 서비스와 유사한 방식으로 개발되지만, UDP의 특성으로 인해 몇 가지 중요한 차이점이 있다:
- 연결 없는 통신: UDP는 연결 설정 과정이 없으므로 connect() 절차가 필요 없다.
- 데이터그램 기반: UDP는 패킷 단위(데이터그램)로 통신하며, 각 패킷은 독립적으로 처리된다.
- 주소 명시: sendto() 메서드 사용 시 목적지 주소를 명시적으로 제공해야 한다.
- 신뢰성 없음: UDP는 패킷 전달을 보장하지 않으므로, 필요에 따라 애플리케이션 수준에서 신뢰성을 구현해야 한다.
이처럼 socketserver 모듈을 활용하면 TCP뿐만 아니라 UDP 기반의 서버도 쉽게 구현할 수 있다. UDP는 실시간 스트리밍, 온라인 게임, DNS 조회 등 지연 시간이 중요하고 일부 데이터 손실이 허용되는 애플리케이션에 적합하다.
UDP Chetting
UDP는 Connection-less 프로토콜이므로, 서버에서 클라이언트들의 정보를 직접 저장하고 관리하는 기능이 필요하다.
이 UDP 채팅 서비스 구현의 주요 특징은 다음과 같다:
- 클라이언트 정보 관리: 서버는 모든 클라이언트의 소켓 정보를 저장하기 위한 데이터베이스(group_queue)를 생성하여 관리한다. 이는 코드의 {CHAT#1} 부분에서 확인할 수 있다.
- 명령어 기반 등록/해제: 클라이언트들은 특수 명령어(#REG, #DEREG)를 통해 서버에 등록하거나 해제하는 절차를 수행한다. 이는 {CHAT#2} 부분에 구현되어 있다.
- '#REG': 클라이언트가 채팅 서비스에 등록하는 명령어
- '#DEREG' 또는 'quit': 클라이언트가 채팅 서비스에서 해제하는 명령어
- 미등록 클라이언트 메시지 차단: 등록되지 않은 클라이언트로부터의 메시지는 처리되지 않는다. 서버는 group_queue에 있는 클라이언트 주소만 처리하고, 그렇지 않은 경우 무시한다. 이는 {CHAT#3} 부분에서 확인할 수 있다.
- 메시지 브로드캐스트: 등록된 클라이언트가 보낸 메시지는 모든 등록된 클라이언트들에게 전달(브로드캐스트)된다. 이는 {CHAT#4} 부분에 구현되어 있다.
UDP 프로토콜의 특성상, TCP와 달리 연결 상태를 유지하지 않기 때문에, 이러한 명시적인 등록/해제 메커니즘이 필요하다. 클라이언트는 채팅 서비스에 참여하기 위해 먼저 '#REG' 명령어를 보내 자신을 등록하고, 나갈 때는 '#DEREG' 또는 'quit' 명령어를 보내 자신을 해제한다.
'학교공부 > 풀스택 서비스 네트워킹' 카테고리의 다른 글
[풀스택 서비스 네트워킹] ZeroMQ (0) | 2025.04.01 |
---|---|
[풀스택 서비스 네트워킹] OSI Architecture L1,L2,L3 (1) | 2025.03.30 |
[풀스택 서비스 네트워킹] OSI Architecture Overall (0) | 2025.03.14 |