소켓 프로그래밍 - 소켓의 구조

Byeonggwan Kang·2021년 9월 9일
0
post-thumbnail

소켓

3장부터는 소켓 프로그래밍에 대해 배웁니다. 이 블로그에서는 제맘대로 해석해서 간략하게 적어보겠습니다.

소켓(socket) API는 프로세스간의 통신을 쉽게 하기 위해 사용한다

운영체제별 차이

소켓 프로그래밍을 할 때에는 OS를 리눅스와 같은 POSIX 계열과 윈도우 계열로 나눕니다. 윈도우에서 SOCKET의 자료형은 포인터인 반면 리눅스는 인덱스의 int값이고, 라이브러리도 윈도우는 WinSock2.h를 쓰며 WSA로 API를 선언/마무리 중간에 에러까지 다루는 반면에 POSIX 계열에서는 sys/socket.h를 사용합니다.

말로 설명하면 기억하기 어렵죠? 그냥 '운영체제별로 소켓 사용하는 방법이 다르구나'하고 넘어간 뒤 다른 운영체제에 이식시켜야 할 때 찾아 봐야겠습니다.



구조

// af	: address family로 보통 IPv4인 AF_INET 사용
// type : TCP or UDP (SOCK_STREAM or SOCK_DGRAM)
// protocol : TCP or UDP. 0으로 하면 type에 맞춰 사용.
SOCKET socket(int af, int type, int protocol);

// 예시
#include <winsock2.h>

using namespace std;

// socket 사용 전에 WSA를 불러와야 한다.
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);

SOCKET udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
SOCKET tcp_socket = socket(AF_INET, SOCK_STREAM, 0);

// 바인딩, 리스닝, ... 소켓 사용
// 에러 관리는 WSAGetLastError() 함수로
// 사용한 뒤 소켓을 닫아줘야 한다
shutdown(tcp_socket, SD_SEND);
closesocket(tcp_socket);
WSACleanup();

양 프로세스 단에서 소켓을 생성한다면 통신 준비가 완료된 것입니다.



주소를 나타내는 방법?

소켓끼리 통신하기 위해서는 주소지가 필요하겠죠? 프로세스 단에서 사용한다고 했으니 상대방의 IP 주소와 포트, 또는 내 프로세스로 오는 패킷을 받는 주소와 포트가 필요합니다. 소켓 API에서는 이를 위해 sockaddr 자료형이 있습니다. 주로 IPv4를 사용하기 위해서 sockaddr_in 자료형을 사용합니다.

sockaddr_in Addr;
// sockaddr_in 초기화
// 연결하고자 하는 목적지의 address family, IP, port 필요
memset(Addr.sin_zero, 0, sizeof(Addr.sin_zero));
Addr.sin_family = AF_INET;
Addr.sin_addr.s_addr = htonl(INADDR_ANY);
Addr.sin_port = htons(51234);

INADDR_ANY는 어떤 IP 주소도 가능한 와일드카드입니다. 보통 나 자신을 표현할 때 사용합니다.

즉 위 예시를 해석하자면 'IPv4와 포트 51234를 사용하는 내 IP 주소'라는 뜻입니다. 주의해야 할점은 htonl, htons같은 함수인데 이 둘의 뜻은 'host to network'이고 바이트 순서 체계를 바꾸는데 사용합니다. 플랫폼마다 빅 엔디안인지 리틀 엔디안인지 다르기 때문에 알아둬야 할 필요가 있습니다.

IP가 아닌 도메인을 조회해 목적지 주소를 알아내는 방법도 있지만 여기서 다루지 않겠습니다. DNS query를 사용하는 과정이 오래 걸리는 편으로 알고 있기 때문에 IP를 그냥 직접 쓰는 게 낫다고 생각했습니다.



마치며

소켓과 소켓 주소 구조체를 알아보았습니다. 이 책에는 자료형 안정성을 보강한 소켓 클래스를 구현한 코드가 있습니다. 인상깊게 보았으나 여기에 굳이 쓰지는 않을 것입니다.

이 다음에는 UDP 소켓과 TCP 소켓으로 데이터를 주고 받는 방법에 대해 알아볼 예정입니다. 블로킹 I/O의 문제점을 해결하는 멀티스레딩과 논블로킹 I/O의 차이에 관해서도 다룰 것입니다. 실제 환경에서는 멀티스레딩과 논블로킹을 섞어 쓴다는데, 어떤 부분에서 뭐가 유리한지 정확히 알 필요가 있어서 자세히 찾아봐야겠습니다.

여유가 된다면 마지막에는 논블로킹(또는 멀티스레딩)으로 채팅 서버 및 클라이언트를 구현해보면서 3장을 마치겠습니다.

1개의 댓글

comment-user-thumbnail
2021년 9월 10일

알고리즘의 선택을 받은 게시글 입니다.

답글 달기