[CS:APP / 11.4] 소켓이란?

정나린·2022년 11월 6일
3
post-thumbnail

CS APP에서 말하는 소켓이란?

  • 리눅스 커널의 관점: 소켓 == 통신의 위한 끝점
  • Unix 프로그램의 관점: 소켓 == 해당 식별자를 가지는 열린 파일

1. 열린 파일이라고?

❣️ 사랑은 열린 문도 아니고 🚪

1. 이전에 이해했던 "소켓"의 개념

  • 전송 계층과 응용 계층 사이에 있는 인터페이스.
  • 프로세스간의 통신을 하기 위한 프로세스 각각의 창구 역할을 하는 애.

그래서. 창구가 뭔데? 실제로 구멍이 나 있는 것도 아니고..!

2. 결국 소켓은 "파일"이다.

1) (CSAPP 10.1 856p) 리눅스에서 파일은 연속된 m개의 바이트이다.
2) (CSAPP 10.1 856p) 네트워크, 디스크, 터미널 같은 모든 I/O 디바이스들은 파일로 모델링되며, 모든 입력과 출력은 해당 파일을 읽거나 쓰는 형식으로 수행된다.
3) (CSAPP 10.2 857p) 소켓은 "네트워크상의 다른 프로세스와 통신하기 위해 사용되는 파일"이다.

파일은 입출력의 추상화이고, 소켓은 다른 프로세스와 통신하기 위한 "파일"이다.

2. 소켓 주소

1. 소켓 주소는 sockaddr_in 타입의 16바이트 "구조체"에 저정된다.

/*Ip socket address structure*/
struct sockaddr_in{
	uint16_t sin_family;
    uint16_t sin_port;  /*16비트 포트 번호*/
    struct in_addr sin_addr; /*32비트 IP 주소*/
    unsigned char sin_zero[8];
}

2. 어떤 종류의 소켓 주소 구조체라도 connect, bind, accept의 함수의 인자로 사용할 수 있어야 하므로, generic한 구조체를 정의하자.

struct sockaddr{
	uint16_t sa_family;
    char sa_data[14]; /* address data */
}
typedef struct sockaddr SA;

cf. connect: 클라이언트서버와의 연결을 수립하기 위해
cf. bind, accept: 서버클라이언트와 연결을 수립하기 위해

3. socket 함수

1. 클라이언트와 서버 모두 소켓 식별자를 생성하기 위해 socket 함수를 호출한다.

cf. 소켓 식별자?
소켓도 일종의 "파일"이라고 했다.
마치 프로세스에도 pid라는 고유번호가 있는 것처럼, 소켓(파일)에도 고유 번호가 필요하다. 그것이 바로 소켓 식별자이다. (fd = file descriptor )

int socket(int domain, int type, int protocol);
/*리턴 값이 음수이면 error, 그렇지 않으면 소켓 식별자(int 형)가 제대로 생성된 것이다. */

2. 클라이언트가 socket함수의 결과로 clientfd를 얻게 될지라도, 아직 "부분적"으로 열린 것 뿐이다.

클라이언트는 서버에게 요청(request)를 보내면서 둘 사이의 통신 사인을 보내긴 하지만, 서버가 요청을 받아들여야(accept)해야 둘 사이의 통신 채널이 만들어지는 것이다.

4. connect 함수

1. 클라이언트는 서버와의 연결을 수립하기 위해 connect 함수를 호출한다.

int connect(int clientfd, const struct sockaddr *addr, socklen_t addrlen);
/*connect가 성공하면 0 리턴, 실패하면 -1 리턴*/

2. connect함수의 3가지 인자

1) int clientfd: 클라이언트가 socket함수의 결과로 리턴받은 클라이언트 소켓 식별자
2) const struct sockaddr *addr: 서버 소켓의 주소
3) socklen_t addrlen: sizeof(sockaddr_in)

3. connect함수가 성공적으로 끝났다면, clientfd는 읽거나 쓸 준비가 된 것이다.

5. bind 함수

1. 서버의 소켓주소와 소켓 식별자와 연결하기 위해 bind함수를 호출한다.

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*bind가 성공하면 0 리턴, 실패하면 -1 리턴*/

6. listen 함수

1. 해당 식별자가 듣기 식별자로 사용할 것을 명시하기 위해 listen 함수를 호출한다.

int listen(int sockfd, int backlog);
/*listen가 성공하면 0 리턴, 실패하면 -1 리턴*/

2. 듣기 식별자?

1) 서버는 클라이언트의 요청이 오기 전부터 열려 있어야 한다.
2) 따라서 특정 클라이언트와의 통신을 위한 소켓뿐만 아니라, 임의의 클라이언트로부터 오는 요청들을 받아올 "웰컴 소켓"이 필요하다.
3) CS APP에서는 이 소켓의 식별자를 listenfd라는 변수 나타낸다.

3. listen함수의 2가지 인자

1) int sockfd: 듣기 식별자로 지정할 소켓 식별자
2) int backlog: 커널이 요청들을 거절하기 전에 "큐"에 저장해야 하는 연결의 수에 대한 정보

7. accept 함수

1. 클라이언트로부터 온 request기 listenfd에 도달하기를 기다리고, 도달했다면 addr 내의 클라이언트의 주소를 채우고, (요청을 보내온) 클라이언트와 통신하기 위한 연결 식별자(connfd) 리턴하기 위해 accept 함수를 호출한다.

int accept(int listenfd, struct sockaddr* addr, int *addrlen);
/*리턴 값이 음수이면 error, 그렇지 않으면 소켓 식별자(int 형)가 제대로 생성된 것이다. */

듣기 식별자(listenfd) vs. 연결 식별자(connfd)
1. 듣기 식별자는 한번 생성되면, 서버가 살아있는 한 계속 존재한다.
2. 연결 식별자는 서버가 클라이언트로부터 오는 연결 요청을 수락할 때마다 생성된다.

4개의 댓글

comment-user-thumbnail
2022년 11월 7일

잘 보고 갑니다~~

1개의 답글
comment-user-thumbnail
2022년 11월 14일

잘 읽었습니다! ㅎㅎ

1개의 답글