소켓 인터페이스
소켓(socket)
통신을 위한 끝점(End point of a connection). 각 소켓은 인터넷 주소와 16비트 정수 포트로 이루어진 소켓 주소를 가지며, address : port 로 나타낸다. 소켓은 모든 운영체제에서 지원한다. (데이터를 주고 받기 위해서 소켓 디스크립터(socket descriptor)라는 파일시스템을 이용한다.)
Berkeley Socket(BSD Socket)
소켓을 파일 식별자(file descriptor)의 형식으로 소켓을 다루는 API. Unix의 철학인 '모든 것은 파일이다'에서부터 출발했다. 네트워크를 포함한 모든 Unix I/O 디바이스들은 파일이므로, 소켓 역시 네트워크 상의 다른 프로세스와 통신하는 역할을 하는 파일로 볼 수 있다. Internet 소켓들은 대부분 이런 BSD 표준을 따른다.
클라이언트의 소켓 주소 내의 포트는 클라이언트가 연결 요청을 할 때 커널이 자동으로 할당한다. 서버의 소켓 주소에 있는 포트는 대개 영구적으로 이 서비스에 연결되는 Well-known port다. (예시- 웹 서버 포트: 80, 이메일 서버 포트: 25 등)
Internet에서 활용되는 인터넷 소켓 주소는 더 구체적인 정보를 담고 있는 16바이트 구조체에 저장된다. IPv4 소켓에서 사용되는 종류이다. 소켓 주소 구조체는 다음과 같다.
// IP socket address structure
struct sockaddr_in { // IPv4 주소를 저장하는 구조체
uint16_t sin_family; // 주소 체계를 저장하는 필드(AF_INET)
uint16_t sin_port; // 포트 정보 저장
struct in_addr sin_addr; // IPv4 주소 저장
unsigned char sin_zero[8]; // 사용하지 않는 필드. 0으로 채움
};
// Generic socket address structure (for connect, bind, and accept)
struct sockaddr {
uint16_t sa_family; // 주소 체계
char sa_data[4]; // 해당 주소 체계에서 사용하는 주소 정보(IP정보 + 포트 정보)
};
sockaddr_in 구조체를 sockaddr 구조체로 캐스팅할 필요가 있을 때는 아래와 같이 사용하면 된다.
// 소켓의 주소를 담는 기본 구조체 틀의 역할(socket.h에 정의되어 있음)
typedef struct sockaddr SA;
소켓 인터페이스 기반 네트워크 응용 프로그램의 개요는 아래의 그림과 같다.
socket( ) 함수
클라이언트와 서버가 소켓(소켓 판별자)를 만들기 위해 사용하는 함수.
int socket(int domain, int type, int protocol)
예시
int clientfd = Socket(AF_INET, SOCK_STREAM, 0);
파라미터
리턴값
bind( ) 함수
서버의 소켓 주소와 프로세스가 만든 소켓을 서로 묶는다. 커널 콜이다. 즉, 커널이 이 역할을 한다.
int bind(int sockfd, sockaddr* addr, socklen_t addrlen);
파라미터
리턴값
클라이언트는 왜 bind()가 필요가 없을까?
listen( ) 함수
어떤 컴퓨터로부터 요청이 와도 수락할 수 있게 대기상태에 들어가도록 하는 함수, 해당 소켓이 서버 소켓임을 알려준다.
int listen(int sockfd, int backlog);
파라미터
리턴값
accpet( ) 함수
서버가 연결 준비가 되었다는 것을 알려주고 연결 request를 받는다.
int accept(int listenfd, SA *addr, int *addrlen);
파라미터
리턴값
connect( ) 함수
서버에 연결 요청하는 함수. 서버가 바쁘면 대기열에 넣었다가 때가 되면 accept
int connect(int clientfd, SA *addr, socklen_t addrlen);
파라미터
리턴값
결과
(x : y, addr.sin_addr : addr.sin_port)
와 같이 소켓 쌍으로 표현할 수 있다.호스트와 서비스 변환
getaddrinfo 함수
getaddrinfo함수는 도메인 주소값을 IP주소값으로 변환할 때 사용하는 함수다. host, service, hint값을 입력하여 result로부터 정보를 추출하는 구조이다.
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
int getaddrinfo(const char *host, // (ex) "www.example.com" or IP
const char *service, // (ex) "http" or port number
const struct addrinfo *hints,
struct addrinfo **result); // DNS서버로부터 받은 네트워크 주소 정보(IP)를 돌려주는 output 매개변수
//Returns: 0 if OK, nonzero error code on error
// 사용 후 메모리 해제(메모리 누수 방지)
void freeaddrinfo(struct addrinfo *result);
addrinfo 구조체
struct addrinfo {
int ai_flags; // 기본 동작을 더 수정하는 비트마스크
int ai_family; // AF_INET -> IPv4, AF_INET6 -> IPv6
int ai_socktype; // TCP 경우 SOCK_STREAM
int ai_protocol;
char *ai_canonname;
size_t ai_addrlen; // 소켓 주소 구조체의 크기
struct sockaddr *ai_addr; // 소켓 주소 구조체 가리킴
struct addrinfo *ai_next; // 다음 addrinfo구조체 가리킴
};
HTTP, Hypertext Transfer Protocol
웹에서 웹 클라이언트(브라우저)와 웹 서버가 서로 정보를 주고받을 수 있는 응용 계층의 프로토콜 중 하나로, TCP/IP 프로토콜을 이용한다.
HTTP는 이미지, 텍스트, 오디오 등 여러 가지 유형의 데이터들을 주고받을 수 있다. 이런 웹 컨텐츠는 MIME 타입으로 인코딩된다.
MIME 타입, Multipurpose Internet Mail Extensions
웹 서버에서 전송되는 여러 종류의 컨텐츠 유형들을 전달하기 위해 필요한 매커니즘이다.
역할
text/html
이라면, 클라이언트는 이 데이터가 html
형식의 텍스트 데이터라는 것을 알 수 있다. MIME 타입의 예Content-Type
HTTP 요청, 응답 메세지의 헤더 중에는 MIME 타입으로 표현된 Content-Type 헤더라는 것이 있다. 이 HTTP 메세지의 바디 데이터를 상대가 어떤 MIME 타입으로 해석해야 할 지를 알려준다.
정적 컨텐츠, 동적 컨텐츠
웹에서 컨텐츠는 단지 파일이다. 웹 서버가 클라이언트에게 컨텐츠를 제공하는 유형을 크게 정적, 동적 컨텐츠로 나눌 수 있다.
URL, Uniform Resource Locator
웹 네트워크 상에 있는 컨텐츠(자원)가 어디 있는지를 알려주는 주소이다. 작게는 웹 페이지, 크게는 컴퓨터 네트워크 상의 모든 자원의 위치를 나타낼 수 있다.
해당 웹 자원의 주소에 접근하려면 해당 URL에 맞는 프로토콜로 접속해야 한다.
http://www.example.com:80/path/to/myfile.html?key1=value1&key2=value2
URL의 prefix
URL의 suffix