과목명 : 컴퓨터 통신(Computer communication)
수업일자 : 2022년 11월 14일 (월)
1. 스레드 핸들(Thread handle)
- 윈도우에서 스레드를 생성할 때는 CreateThread() API 함수를 사용합니다. CreateThread() 함수는 스레드를 생성한 후 핸들을 리턴하며 스레드 핸들은 파일 디스크립터 또는 소켓 디스크립터와 비슷한 개념으로 운영체제의 스레드 관련 데이터 구조체를 간접적으로 참조하는 매개체와 같은 역할을 합니다. 이를 통해 다양한 방식으로 스레드를 제어할 수 있게 됩니다.
2. 스레드 동기화(Synchronization)
2-1. 스레드 동기화의 필요성
- 멀티 스레드를 이용하는 응용 프로그램에서 두 개 이상의 스레드가 하나의 공유 데이터에 접근하면 다양한 문제가 발생할 수 있습니다. 이러한 문제로 멀티 스레드에서 동기화는 빠질 수 없는 핵심적인 요소입니다.
- 여기서 두 개 이상의 스레드가 하나의 공유변수를 사용하는 시나리오를 생각해 볼 수 있습니다.
공유 변수 : int share_variable = 1000;
스레드 1의 코드
(a) read share_variable into ECX
(b) ECX = ECX + 2000
(c) write ECX into share_variable
스레드 2의 코드
(a) read share_variable into ECX
(b) ECX = ECX + 4000
(c) write ECX into share_variable
- 만약 스레드 1이 (a)를 실행한 상태에서 정지되고 스레드 2가 (a)~(c)를 수행하면 share_variable의 값은 5000이 됩니다. 다시 스레드 1이 CPU로부터 자원을 할당받아 (b)~(c)를 수행하면 ECX에 저장되어 있던 값에 2000이 더해지고 해당 값이 메모리에 저장되어 share_varialbe의 값은 3000이 됩니다. 이에 따라 스레드 2가 더한 값인 5000은 사라지게 되었습니다.
- 이처럼 멀티 스레드 환경에서 발생하는 문제를 해결하기 위한 일련의 작업을 스레드 동기화(Synchronization)라고 합니다. 윈도우 운영체제에선 상황에 따라 적절한 스레드 동기화 기법을 선택할 수 있도록 다양한 API를 제공하고 있습니다.
2-2. 스레드 동기화 기법
- 윈도우 운영체제에서 사용할 수 있는 대표적인 스레드 동기화 기법입니다.
- 임계 영역(Critical section), 뮤텍스(Mutex), 이벤트(Event), 세마포어(Semaphore), 대기 가능 타이머(Waitable timer)
동기화 종류 | 동기화 기능 |
임계 영역 (Critical section) |
공유 자원에 대해 오직 한 스레드의 접근만 허용한다. (한 프로세스에 속한 스레드 간에만 사용 가능) |
뮤텍스 (Mutex) |
공유 자원에 대해 오직 한 스레드의 접근만 하용한다. (서로 다른 프로세스에 속한 스레드 간에도 사용 가능) |
이벤트 (Event) |
이벤트 발생을 알려 대기 중인 스레드를 깨운다. |
세마포어 (Semaphore) |
한정된 개수의 자원에 여러 스레드가 접근할 때, 자원을 사용할 수 있는 스레드의 개수를 제한한다. |
대기 가능 타이머 (Waitable timer) |
정해진 시간이 되면 대기 중인 스레드를 깨운다. |
2-3. 스레드 동기화의 기본 개념
- 스레드 동기화가 필요한 상황은 크게 다음 두 경우입니다.
(1) 두 개 이상의 스레드가 공유 자원에 접근한다.
(2) 한 스레드가 작업을 완료한 후, 대기 중인 다른 스레드에게 알려준다.
- 두 경우 모두 각 스레드가 독립적으로 실행되지 않고 다른 스레드와의 상호 작용을 토대로 자신의 작업을 수행한다는 특징이 존재합니다.
- 스레드를 동기화하려면 스레드가 상호 작용을 해야 하므로 아래의 그림과 같이 중간 매개체의 역할이 필요합니다. 두 스레드가 동시에 진행하면 안 되는 상황이 있을 때 두 스레드는 매개체를 통해 진행 가능 여부를 판단하고 이를 바탕으로 자신의 작업을 수행할지를 결정합니다.
3. UDP 서버-클라이언트 구조
3-1. UDP 프로토콜 개요
- TCP와 더불어 전송 계층의 주요 프로토콜인 UDP 프로토콜을 통해 소켓 프로그래밍이 가능합니다.
- TCP, UDP 프로토콜은 전송 계층 프로토콜이라는 점에서 아래와 같은 공통점이 존재합니다.
(공통점 1) : 포트 번호를 이용해 주소를 지정합니다.
- 두 응용 프로그램이 TCP나 UDP를 이용해 통신하려면 반드시 포트 번호를 결정해야 합니다.
(공통점 2) : 데이터 오류를 체크합니다.
- TCP와 UDP는 IP의 패킷 전송을 기반으로 동작하며 전송 중 여러 원인으로 오류가 발생할 수 있는데, IP는 프로토콜 동작에 필수적인 IP 헤더에 대해서만 오류를 체크하고 데이터는 체크하지 않습니다.
- 반면 TCP와 UDP는 헤더는 물론 데이터에 대한 오류 여부까지 체크합니다.
- 아래 표는 TCP와 UDP의 특징을 정리한 표입니다.
TCP(Transmission Control Protocol) | UDP(User Datagram Protocol) |
연결형(Connection-oriented) 프로토콜 - 연결 설정 후 통신 가능 |
비연결형(Connectionless) 프로토콜 - 연결 설정 없이 통신 가능 |
신뢰성 있는 데이터 전송 기능 보장 - 데이터 재전송이 가능 |
신뢰성 없는 데이터 전송 기능 - 데이터를 재전송하지 않음 |
일대일 통신(Unicast) | 일대일 통신(Unicast), 일대다 통신(Broadcast, Multicast) |
데이터 경계를 구분하지 않음 - 바이트 스트림(Byte stream) 서비스 |
데이터 경계를 구분함 - 데이터그램(Datagram) 서비스 |
3-2. UDP 항목별 특징을 소켓 함수의 관점에서 바라본 경우
(1) 연결 설정을 하지 않으므로 connection() 함수를 사용하지 않습니다.
- 일부 환경에서 사용될 수는 있으나, 비연결형 프로토콜이기에 해당 함수를 호출하더라도 패킷 교환이 일어나진 않음
(2) 프로토콜 수준에서 신뢰성 있는 데이터 전송 기능을 보장할 수 없으므로 필요하다면 응용 프로그램의 수준에서 직접 신뢰성이 보장되는 데이터 전송 기능을 구현해야만 합니다.
(3) 간단한 소켓 함수의 호출 절차만 따르면 Broadcast, Multicast 통신을 쉽게 구현할 수 있습니다.
(4) TCP와 달리 데이터 경계 구분을 위한 작업을 별도로 할 필요가 없습니다.
3-3. UDP 서버-클라이언트의 동작 원리
(a)
- 서버는 소켓을 생성하고 클라이언트가 데이터를 보내기를 기다리고 있습니다. 이때 서버는 특정 포트 번호와 연결되어 있어서 해당 포트 번호로 도착한 데이터만 수신 가능합니다.
(b)
- 첫 번째 클라이언트는 연결 설정 없이 서버와 바로 데이터를 주고받습니다.
(c)
- 두 번째 클라이언트도 연결 설정 없이 서버와 바로 데이터를 주고받습니다. TCP 서버와 달리 UDP 서버는 소켓을 한 개만 사용합니다.
(d)
- UDP 서버-클라이언트가 통신하는 일반적인 상황이며 "UDP 클라이언트 #n"처럼 한 클라이언트가 소켓 두 개 이상을 사용해 서버와 통신할 수 있습니다.
4. UDP 서버-클라이언트 모델
4-1. UDP 서버-클라이언트 동작 모델
- 일반적으로 UDP 서버와 클라이언트는 아래와 그림과 같이 각각 나열된 순서로 소켓 함수를 호출합니다.
- UDP 서버
(1) socket() 함수로 소켓을 생성하며 사용할 프로토콜을 결정합니다.
(2) bind() 함수로 지역 IP 주소와 지역 포트 번호를 결정합니다.
(3) 클라이언트 측에서 보낸 데이터를 recvfrom() 함수로 받으며 이때 클라이언트의 주소(원격 IP 주소, 포트 번호) 정보를 확인할 수 있습니다.
(4) 받은 데이터의 처리 결과를 sendto() 함수로 전달합니다.
(5) 모든 작업 완료 시 closesocket() 함수로 소켓을 종료합니다.
- UDP 클라이언트
(1) socket() 함수로 소켓을 생성하며 사용할 프로토콜을 결정합니다.
(2) sendto() 함수로 서버에 데이터를 보냅니다. 이때 원격 IP 주소와 포트 번호, 지역 IP 주소와 포트 번호까지 결정됩니다.
(3) 서버가 처리해 보낸 데이터를 recvfrom() 함수로 받습니다.
(4) 모든 작업 완료 시 closesocket() 함수로 소켓을 종료합니다.
4-2. UDP 데이터 전송 함수
(1) sendto() 함수
- 응용 프로그램의 데이터를 운영체제의 송신 버퍼에 복사함으로써 데이터를 전송합니다.
int sendto(
SOCKET s,
const char *buf,
int len,
int flags,
const struct sockaddr *to, // 누구에게 보내는지에 대한 주소 정보
int tolen
);
- const struct sockaddr *to : 목적지 주소를 보유한 소켓 구조체입니다.
(2) recvfrom() 함수
- 운영체제의 수신 버퍼에 도착한 데이터를 응용 프로그램의 버퍼에 복사하는 함수입니다.
- TCP의 recv() 함수와 달리 UDP의 recvfrom() 함수는 패킷 데이터를 한 번에 하나만 읽을 수 있습니다.
int recvfrom(
SOCKET s,
char *buf,
int len,
int flags,
struct sockaddr *from, // 누구에게 받았는지에 대한 주소 정보
int *fromlen
);
- struct sockaddr *from : 소켓 구조체를 전달하면 송신자의 주소 정보(IP 주소, 포트 번호)로 채워집니다.
5. 브로드캐스팅(Broadcasting)
- TCP 프로토콜과 구별되는 특징으로 UDP 프로토콜에선 브로드캐스팅, 멀티캐스팅이 있습니다. 이를 이용해 일대다 통신을 쉽게 구현할 수 있게 됩니다.
5-1. 브로드캐스팅의 정의
- 브로드캐스팅(Broadcasting)은, 송신 호스트가 전송한 데이터가 네트워크에 연결된 모든 호스트에게 전송되는 방식을 의미합니다.
5-2. 여러 가지 데이터 전송 방식들
(1) 유니캐스트(Unicast)
- TCP를 기반으로 하나의 호스트가 다른 한 호스트에게 데이터를 전송하는 방식입니다.
- IPv4, IPv6에서 모두 지원합니다.
(2) 브로드캐스팅(Broadcasting, one-to-many)
- UDP를 기반으로 하나의 호스트가 네트워크에 연결된 모든 호스트에게 데이터를 전송하는 방식입니다.
- IPv4, IPv6에서 모두 지원합니다.
(3) 멀티캐스팅(Multicasting, one-to-many)
- UDP를 기반으로 동일한 그룹에 가입한 모든 호스트에게 데이터를 전송하는 방식입니다.
- 동일한 그룹이란, 해당 그룹의 데이터를 송신 받기로 한 수신자들의 모임으로 생각할 수 있습니다.
- IPv4, IPv6에서 모두 지원합니다.
(4) 애니캐스팅(Anycasting, one-to-one-of-many)
- 하나의 호스트가 동일 그룹에 속한 개체 중, 가장 가까운 호스트에게 데이터를 보내면 데이터를 받은 호스트가 해당 그룹에 속한 나머지 호스트에게 데이터를 전송하는 방식입니다.
- IPv6에서만 지원합니다.
- 학부에서 수강했던 전공 수업 내용을 정리하는 포스팅입니다.
- 내용 중에서 오타 또는 잘못된 내용이 있을 시 지적해 주시기 바랍니다.
'전공 수업 > 컴퓨터 통신(Computer Communication)' 카테고리의 다른 글
[14주 차] - 소켓 옵션 관련 함수, 멀티캐스팅과 브로드캐스팅 (0) | 2022.12.02 |
---|---|
[10주 차] - 프로세스와 스레드(Process and Thread), 멀티 스레드(Multi-thread) (0) | 2022.11.06 |
[9주 차] - 디버깅(Debugging), 소켓의 Blocking, Non-Blocking & Synchronous, Asynchronous (0) | 2022.10.24 |
[8주 차] - TCP 서버 - 클라이언트의 동작, 여러 가지 함수 (0) | 2022.10.17 |
[7주 차] - TCP 서버 - 클라이언트의 동작, 여러 가지 함수 (0) | 2022.10.11 |
댓글