. 11.4 소켓 인터페이스 (작성 중)
본문 바로가기
프로그래밍 공부/CSPP

11.4 소켓 인터페이스 (작성 중)

by 불냥이_ 2021. 2. 1.

 

그림 1. 소켓 인터페이스 기반 네트워크 응용프로그램 개요

 소켓 인터페이스는 네트워크 응용프로그램을 만들기 위한 Unix I/O 함수들과 함께 사용되는 함수들의 집합이다. 그림 1은 전형적인 소켓 인터페이스의 개요를 보여준다.

 

※ 이 글에서 [TCP-IP/공부]주소정보의 표현 : 네이버 블로그 (naver.com) 를 참고했다. 아직 고등학생인데 나랑 같이 이거를 하다니. 한국 IT의 미래가 밝다. 

 

 

11.4.1 소켓 주소 구조체 

 리눅스 커널의 관점에서 보면 소켓은 통신을 위한 끝점이고, Unix 프로그램의 관점에서 보면 해당 식별자를 가지는 열린 파일이다.

 

/* IP socket address structure */
struct sockaddr_in {
	uint16_t sin_family; /* Protocol family (always AF_INET) */
	uint16_t sin_port; /* Port number in network byte order */
	struct in_addr sin_addr; /* IP address in network byte order */
	unsigned char sin_zero[8]; /* Pad to sizeof(struct sockaddr) */
};

/* Generic socket address structure (for connect, bind, and accept) */
struct sockaddr {
	uint16_t sa_family; /* Protocol family */
	char sa_data[14]; /* Address data */
};

그림 2. 소켓 주소 구조체

 

 인터넷 소켓 주소는 그림 2와 같이 16바이트의 구조체로 저장된다. 

sin_family : 항상 AF_INET으로 정한다.

sin_port : 16비트 포트 번호 (네트워크 바이트 순서) 주의해야할 것은 0~65535 (2^16-1) 지정해주어야하며, 0~1023 (2^10-1) 은 Well-Known Port라고 불린다. 이미 다른 프로그램에서 사용하도록 되어있으므로, 포트 1024~65535 까지 지정하도록 해야한다. 

sin_addr : 32비트 IP 주소 (그림 3 참조) (네트워크 바이트 순서)

 

/* IP address structure */
struct in_addr {
uint32_t s_addr; /* Address in network byte order (big-endian) */
};

그림 3. in_addr 구조체

 

 connect, bind, accept 함수는 프로토콜에 특화된 소켓 주소 구조체를 가리키는 포인터를 필요로 한다. 그래서 우리는 다음과 같이 sockaddr을 지정하겠다.

typedef struct sockaddr SA;

 

11.4.2 socket 함수

#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
	Returns: nonnegative descriptor if OK, −1 on error

 클라이언트와 서버는 소켓 식별자를 생성하기 위해서 socket 함수를 사용한다.

만약 소켓을 끝점으로 만들고 싶다면, 다음과 같이 하드코드된 인자로 socket 함수를 호출하면 된다.

 

clientfd = Socket(AF_INET, SOCK_STREAM, 0);

 sockect의 인자 중에서

AF_INET : 지금 32비트 IP주소를 사용하고 있다는 것을 나타낸다. 

 ( AF_INET 외에 들어갈 수 있는 인자는 다음과 같다.

AF_INET : IPv4 인터넷 프로토콜 체계에 적용하는 인터넷 주소 체계

AF_INT6 : IPv6 인터넷 프로토콜 체계에 적용하는 인터넷 주소 체계

AF_LOCAL : UNIX 인터넷 플토콜 체계에 적용하는 인터넷 주소 체계 )

 

SOCK_STREAM : 소켓이 인터넷 연결의 끝점이 될 것이라는 것을 나타낸다. 하지만, 가장 좋은 선택지는 getaddrinfo 함수를 이용하여 코드가 프로토콜에 무관하게 되도록 하는 것인데 하기에서 설명하겠다.

 

 이것만으로는 데이터를 전부 읽을 수 없다. 또, 소켓의 ㅗ프 과정을 어떻게 완료하는지는 클라이언트인지 서버인지에 따라 다르다. 

 

 

11.4.3 Connect 함수

#include <sys/socket.h>
int connect(int clientfd, const struct sockaddr *addr,
socklen_t addrlen);
	Returns: 0 if OK, −1 on error

 connect 함수는 소켓 주소 addr의 서버와 인터넷 연결을 시도하며, addrlen은 sockaddr_in의 사이즈가 된다. connect 함수는 연결이 성공할 때 까지 블록되어 있거나 에러가 발생한다. 성공한다면 clinetfd 식별자는 읽거나 쓸 준비가 되었으며, 이 연결은 다음과 같은 소켓 쌍으로 규정된다.

(x:y, addr.sin_addr:addr.sin_port)

 여기서 x는 클라이언트 IP의 주소이고, y는 클라이언트 호스트의 클라이언트 프로세스를 유일하게 식별하는 단기 포트다. socket에서처럼 가장 좋은 방법은 getaddrinfo를 이용하여 connect의 인자를 제공하는 것이다. 

 

11.4.4 bind함수

#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
		Returns: 0 if OK, −1 on error

 bind 함수는 커널에서 addr에 있는 서버의 소켓 주소를 소켓 식별자 sockfd와 연결하라고 물어본다. addrlen인자는 sizeof(sockaddr_int)이다. socket 과 connect에서와 마찬가지로 etaddrinfo를 이용해서 bind 인자를 제공한다. 

 

 11.4.5 listen 함수

#include <sys/socket.h>
int listen(int sockfd, int backlog);
		Returns: 0 if OK, −1 on error

 listen 함수는 sockfd 를 능동 소켓에서 듣기 소켓으로 변환하며, 듣기 소켓은 클라이언트로부터의 연결 요청을 승락할 수 있다. 

backlog : 커널이 요청들을 거절하기 전에 큐에 저장해야 하는 연결의 수에 대한 정보를 제공한다. 이 인자의 정확한 의미는 훨씬 고수준이므로 논의하지 않을 것이며 기본값 1024로 설정한다. 

 

11.4.6 accept 함수

 서버는 accept 함수를 호출해서 클라이언트로부터의 연결 요청을 기다린다.

#include <sys/socket.h>
int accept(int listenfd, struct sockaddr *addr, int *addrlen);
		Returns: nonnegative connected descriptor if OK, −1 on error

 accept함수는 클라로부터 연결 요청이 듣기 식별자 listenfd에 도달하기를 기다리고, 그 후에 addr 내의 클라의 Unix I/O 함수들을 사용해서 클라와 통신하기 위해 사용될 수 있는 연결 식별자를 리턴한다. 

 듣기 식별자와 연결 식별자의 구분은 어떻게 해야하는가?

 듣기 식별자는 클라 연결 요청에 대해 끝점으로서 역할을 한다. 처음에 한 번 생성되고 서버가 살아있는 동안 계속 존재한다. 

 연결 식별자는 클라와 서버 사이의 연결의 끝점이다. 서버가 연결 요청;connect를 수락할 때마다 생서되며, 서버가 클라에 서비스 하는 동안만 존재한다. 

 

GetAddrInfo 함수

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

int getaddrinfo(const char *host, const char *service,const struct addrinfo *hints, struct addrinfo **result);
		Returns: 0 if OK, nonzero error code on error

void freeaddrinfo(struct addrinfo *result);
		Returns: nothing

const char *gai_strerror(int errcode);
		Returns: error message

getaddrinfo 함수의 인자는 다음과 같다.

host : 도메인 이름과 숫자 주소를 모두 받을 수 있게 한다. 

service : 서비스 이름(http 등) 이거나 십진수 포트번호가 들어갈 수 있다. 호스트이름을 주소로 변환하고 시지 않을 때는 host를 NULL로 설정하 수 있다. 

hints : 힌트는 필요할 때 넣을 수 있는 인자이다. 

struct addrinfo {
	int ai_flags; /* Hints argument flags */
	int ai_family; /* First arg to socket function */
	int ai_socktype; /* Second arg to socket function */
	int ai_protocol; /* Third arg to socket function */
	char *ai_canonname; /* Canonical hostname */
	size_t ai_addrlen; /* Size of ai_addr struct */
	struct sockaddr *ai_addr; /* Ptr to socket address structure */
	struct addrinfo *ai_next; /* Ptr to next item in linked list */
};

 위에서 많이 사용했던 Getaaddrinfo 

댓글