출처 : 윤성우의 열혈 TCP/IP 소켓 프로그래밍
소켓 생성시 필요한 매개변수
첫번째, 두번째 인자로 전달된 정보를 통해 소켓의 프로토콜이 사실상 결정되기 때문에 세번째 인자로 0을 전달해도 된다.
프로토콜 체계
소켓의 타입
1. SOCK_STREAM
- 중간에 데이터가 소멸되지 않고 목적지로 전송된다.
- 전송 순서대로 데이터가 수신된다.
- 전송되는 데이터의 경계가 존재하지 않는다
- 여러번의 write 함수호출을 통해 전송된 데이터를 한번의 read 함수 호출을 통해 전부 수신할 수 있고, 반대로 한번의 write 함수호출을 통해 전송된 데이터를 여러번의 read 함수 호출을 통해 수신할 수 있다.
- write/read 함수 호출 횟수가 큰 의미를 갖지 못한다.
- 수신된 데이터는 소켓에 존재하는 버퍼에 저장되고, read 함수 호출을 통해 데이터가 읽혀지면 그만큼 버퍼에서 비워지게 된다.
- read 함수 호출로 읽혀지는 양보다 많은 양의 데이터가 수신되어 버퍼가 꽉 찼다고 해도 연결지향형 소켓은 데이터를 전송하는 영역의 소켓이 상대 소켓의 상태를 봐가며 전송하기 때문에 데이터 손실은 발생하지 않는다.
- 소켓의 연결은 반드시 1대 1이어야 한다.
2. SOCK_DGRAM
- 전송된 순서에 상관없이 빠른 속도의 전송을 지향한다.
- 전송된 데이터는 손실과 파손의 우려가 있다.
- 전송되는 데이터의 경계가 존재한다.
- 한번에 전송할 수 있는 데이터의 크기가 제한된다.
IPv4 주소체계
IP 주소의 첫번째 바이트만 참조해도 네트워크 주소가 몇 바이트인지 판단이 가능하다.
클래스 A의 첫번째 바이트 범위 0~127
클래스 B의 첫번째 바이트 범위 128~191
클래스 C의 첫번째 바이트 범위 192~223
IP주소 기반 데이터 전송과정
203.211.217.202 로 데이터를 전송한다고 하면 처음 203.211.217 네트워크로 데이터를 전송하고, 해당 네트워크를 구성하는 라우터는 전송된 데이터의 호스트 주소를 참조하여 .202 로 데이터를 전송해준다.
라우터와 스위치
외부로부터 수신된 데이터를 호스트에 전달하고, 호스트가 전달한 데이터를 외부로 송신해주는 물리적 장치가 라우터 또는 스위치이다. 라우터보다 기능적으로 작은 것을 가리켜 스위치라 부르는데 사실상 같은 의미로 사용된다.
Port 번호에 의한 소켓의 구분 과정
IP만 있어도 목적지 컴퓨터로 데이터를 전송할 수 있지만 데이터를 수신해야 하는 최종 목적지인 응용프로그램에까지 데이터를 전송하기 위해 Port번호가 필요하다.
- PORT번호는소켓을 구분하는 용도로 사용되기 때문에 하나의 운영체제 내에서 동일한 Port 번호를 둘 이상의 소켓에 할당할 수 없다.
- 하나의 프로그램 내에서는 둘 이상의 소켓이 존재할 수 있으므로, 둘 이상의 Port가 하나의 프로그램에 할당될 수 있다.
- Port번호는 16비트로 표현하며 범위는 0~65535 이다.
- 0~1023은 Well-known Port 로 이미 용도가 결정되어 있어 이 번호를 피해서 사용한다.
- TCP 소켓과 UDP 소켓은 Port 번호를 공유하지 않기 때문에 중복되어도 상관없다.
IPv4 기반 주소표현을 위한 구조체
struct sockaddr_in
{
sa_family_t sin_family; // 주소체계(Address family)
uint16_t sin_port; // 16비트 TCP/UDP Port번호
struct in_addr sin_addr; // 32비트 IP주소
char sin_zero[8]; // 사용되지 않음
};
- sin_family : 주소체계로 전달될 수 있는 값은 AF_INET, AF_INET6, AF_LOCAL 이 있고 IPv4 인터넷 프로토콜에 적용하는 주소체계는 AF_INET이 해당된다.
- sin_port : 16비트 Port 번호. 네트워크 바이트 순서로 저장되야한다.
- sin_addr : 32비트 IP주소 정보. 네트워크 바이트 순서로 저장되야한다.
- sin_zero : sockaddr_in 구조체의 크기를 sockaddr 과 일치시키기 위해 삽입된 멤버이며 반드시 0으로 채워져야 한다.
struct in_addr
{
in_addr_t s_addr;
};
bind 함수의 두번째 매개변수로 전달되는 것은 위에서 소개한 sockaddr_in이 아니라 sockaddr 구조체 변수의 주소값이다. sockaddr 구조체변수는 IPv4 만 아니라 이외의 주소정보도 담을 수 있는 구조체지만 구조를 살펴보면 정보를 담기에 불편하게 정의되어 있다.
때문에 sockaddr과 동일한 바이트 열을 편하게 구성하기 위해 정의된 구조체가 sockaddr_in이다.
struct sockaddr
{
sa_family_t sin_family; // 주소체계
char sa_data[14]; // 주소정보
};
바이트 순서
빅 엔디안 : 상위 바이트 값을 작은 번지수에 저장하는 방식
리틀 엔디안 : 상위 바이트 값을 큰 번지수에 저장하는 방식
호스트 바이트 순서 : CPU별 데이터 저장방식
네트워크 바이트 순서 : 통일된 데이터 송수신 기준. 빅 엔디안
바이트 변환 함수
h는 host, n은 network를 의미하고 s는 short, l은 long을 의미한다.
unsigned short htons(unsigned short);
unsigned short ntohs(unsigned short);
unsigned long htonl(unsigned long);
unsigned long ntohl(unsigned long);
✔ 데이터 송수신 과정에서는 네트워크 바이트 순서로 자동 변환이 이뤄지기 때문에 sockaddr_in 구조체 변수에 데이터를 채울 때만 바이트 순서를 신경쓰면 된다.
문자열 정보를 네트워크 바이트 순서 정수로 변환하는 함수
ex.
char *addr = "192.168.1.3";
unsigned long conv_addr = inet_addr(addr);
printf("%#lx\n", conv_addr);
INADDR_ANY : 현재 실행중인 컴퓨터의 IP를 소켓에 부여할 때 사용
소켓에 인터넷 주소 할당 : bind()
'프로그래밍 > C' 카테고리의 다른 글
C ] strtol, strtoul : 정수 문자열을 진수 선택하여 long/unsigned long 값으로 변환 (2진수, 8진수, 10진수, 16진수) (0) | 2023.01.15 |
---|---|
C ] strtok, strtok_r : 구분 문자로 문자열 쪼개기 (0) | 2023.01.15 |
윈도우 소켓 ] TCP 에코 서버, 클라이언트 및 동작원리 (0) | 2023.01.01 |
윈도우 소켓 ] UDP 서버, 클라이언트 (0) | 2022.12.27 |
윈도우 소켓 ] Winsock 라이브러리 링크하기 (0) | 2022.12.16 |