커널에서
애플리케이션에서
클라이언트와 서버는 소켓 디스크립터를 읽고 써서 통신한다.
일반 파일 I/O와 소켓 I/O를 구분하는 가장 큰 차이는, 애플리케이션이 소켓 디스크립터를 어떻게 open 하는지에 따른다.
일반적인 소켓 주소
struct sockaddr {
uint16_t sa_family; /* Protocol family */
char sa_data[14]; /* Address data. */
};
connect, bind, accept의 인자 중 주소로 전달될 때 사용한다.
소켓 인터페이스가 디자인 되었을 당시 generic pointer(void *)라는 개념이 없어서 나왔다.
캐스팅의 편의성을 위해 다음과 같은 컨벤션을 쓴다.
typedef struct sockaddr SA;
Internet-specific 소켓 주소
struct sockaddr_in {
uint16_t sin_family; /* Protocol family (always AF_INET) */
uint16_t sin_port; /* Port num in network byte order */
struct in_addr sin_addr; /* IP addr in network byte order */
unsigned char sin_zero[8]; /* Pad to sizeof(struct sockaddr) */
};
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
// 정상적인 경우 디스크립터를 리턴한다 (양수). 아닐 경우 -1을 리턴한다.
소켓 식별자를 생성하기 위해 사용한다.
소켓을 끝점으로 만들 경우 다음과 같이 호출해서 쓴다.
clientfd = Socket(AF_INET, SOCK_STREAM, 0)
// AF_INET : 32비트 IP주소를 사용한다.
// SOCK_STREAM : 소켓이 인터넷 연결의 끝점이 될 것이다.
클라이언트가 호출하여, 서버와의 연결을 수립한다.
#include <sys/socket.h>
int connect(int clientfd, const struct sockaddr *addr, socklen_t addrlen);
// 정상작동 시 0 리턴, 아닐 경우 -1 리턴
// clientfd : 연결하고자 하는 클라이언트의 디스크럽터
// addr : 연결하고자 하는 서버의 소켓 주소
// addrlen : sizeof(sockaddr_in). 구조체의 크기