11.4절: 소켓 인터페이스 (The Sockets Interface)
소켓 인터페이스는 네트워크 응용 프로그램을 구축하기 위해 Unix I/O 함수들과 함께 사용하는 함수 집합이다. 거의 모든 현대 시스템(Unix, Windows, macOS 등)에 구현되어 있으며, 클라이언트-서버 트랜잭션에서 다음과 같은 흐름을 갖는다:
- 클라이언트와 서버는 각각 socket() 함수를 호출하여 소켓을 생성한다.
- 서버는 bind()와 listen()을 통해 포트를 열고 연결을 대기한다.
- 클라이언트는 connect()를 호출하여 서버에 연결을 요청한다.
- 서버는 accept()를 통해 클라이언트의 연결 요청을 수락한다.
- 양측은 rio_readlineb, rio_writen 등을 이용해 데이터를 주고받는다.
- 연결이 끝나면 close()를 통해 소켓을 닫는다.
11.4.1: 소켓 주소 구조체 (Socket Address Structures)
소켓은 커널 관점에서는 통신 종단점이며, 프로그램 관점에서는 파일 디스크립터처럼 사용된다. IP 기반 인터넷 소켓 주소는 sockaddr_in 구조체에 저장된다:
struct sockaddr_in {
uint16_t sin_family; // 프로토콜 패밀리 (AF_INET)
uint16_t sin_port; // 포트 번호 (네트워크 바이트 순서)
struct in_addr sin_addr; // IP 주소 (네트워크 바이트 순서)
unsigned char sin_zero[8]; // 패딩
};
소켓 관련 함수들 (connect, bind, accept)은 이 구조체를 struct sockaddr *로 캐스팅하여 전달해야 한다.
11.4.2: socket() 함수
소켓을 생성하는 함수:
int socket(int domain, int type, int protocol);
예: socket(AF_INET, SOCK_STREAM, 0)는 IPv4 TCP 연결을 위한 소켓을 생성한다.
11.4.3: connect() 함수
클라이언트가 서버와 연결할 때 사용하는 함수:
int connect(int clientfd, const struct sockaddr *addr, socklen_t addrlen);
지정된 서버 주소로 연결을 시도하며, 연결이 성공하면 읽기/쓰기가 가능한 상태가 된다.
11.4.4~6: 서버 측 함수
- bind(): 소켓을 IP 주소와 포트에 바인딩한다.
- listen(): 연결 요청을 대기 상태로 설정한다.
- accept(): 클라이언트의 연결 요청을 수락하고 새로운 소켓을 생성한다.
11.4.7: 호스트 및 서비스 변환 (Host and Service Conversion)
getaddrinfo 함수는 문자열 형식의 호스트 이름과 서비스 이름(또는 포트 번호)을 바이너리 소켓 주소 구조체로 변환한다. 이는 구식 함수인 gethostbyname이나 getservbyname을 대체하며, 스레드 안전하고 프로토콜 독립적이다.
int getaddrinfo(const char *host, const char *service,
const struct addrinfo *hints,
struct addrinfo **result);
- host: 도메인 이름 또는 IP 주소 문자열
- service: 포트 번호 또는 서비스 이름 (예: "http")
- hints: 필터링 조건 (IPv4만, TCP만 등)
- result: 결과 주소 구조체 리스트 포인터
또한 getnameinfo 함수는 소켓 주소를 다시 도메인 이름과 서비스 문자열로 역변환한다:
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen,
char *service, size_t servlen, int flags);
11.4.8: 헬퍼 함수들 (Helper Functions)
소켓 프로그래밍을 단순화하기 위해, 다음과 같은 헬퍼 함수가 정의된다:
open_clientfd
클라이언트 측에서 사용하며, 서버에 연결된 소켓 디스크립터를 반환한다.
int open_clientfd(char *hostname, char *port);
- 내부적으로 getaddrinfo, socket, connect를 호출한다.
- 실패한 경우에도 자원을 해제하고 종료한다.
open_listenfd
서버 측에서 사용하며, 지정된 포트에서 연결 요청을 수신할 수 있는 리스닝 소켓을 만든다.
int open_listenfd(char *port);
- getaddrinfo의 AI_PASSIVE 플래그와 함께 호출되며, 와일드카드 주소로 바인딩된다.
- listen()까지 호출하여 준비된 리스닝 디스크립터를 반환한다.
11.4.9: 에코 클라이언트와 서버 예제
가장 좋은 학습 방법은 실제 코드를 보는 것이다. 이 절에서는 다음과 같은 두 예제를 제공한다:
- 에코 클라이언트: 표준 입력으로부터 한 줄을 읽고, 이를 서버로 전송한 뒤 다시 회신된 텍스트를 출력한다. EOF가 입력되면 종료된다.
- 에코 서버: 클라이언트 연결을 수락한 후, 클라이언트가 보낸 데이터를 되돌려주는 echo() 루틴을 호출한다. 이 과정은 무한 루프 내에서 반복된다.
이 예제를 통해 소켓 API의 사용 패턴을 명확히 이해할 수 있으며, 이후 병렬 서버 구현의 기반이 된다.
'크래프톤 정글 (컴퓨터 시스템: CSAPP) > 11장 네트워크 프로그래밍' 카테고리의 다른 글
컴퓨터 시스템 : CSAPP 11장 정리 - 11.6 종합설계 :소형 웹 서버 Part.2 (2) | 2025.05.03 |
---|---|
컴퓨터 시스템 : CSAPP 11장 정리 - 11.6 종합설계 :소형 웹 서버 Part.1 (0) | 2025.05.03 |
컴퓨터 시스템 : CSAPP 11장 정리 - 11.5 웹 서버 이론편 (0) | 2025.05.03 |
컴퓨터 시스템 : CSAPP 11장 정리 - 11.3 글로벌 IP 인터넷 (0) | 2025.05.02 |
컴퓨터 시스템 : CSAPP 11장 정리 - 11.1 ~ 11.2 (1) | 2025.05.02 |