tcp는 연결 지향 방식이다.
socket 함수를 이용해 소켓을 생성한다
생성된 소켓에 bind 함수를 통해 주소를 할당한다
int bind(int 소켓 디스크립터, struct sockaddr* 구조체 변수의 주소값, socklen_t 구조체 변수의 길이정보);
BUT 만약 서버가 bind를 하지 않으면, 커널은 소켓에 대한 일시적인 포트를 선택한다
클라이언트는 bind를 하지 않는다.
그래서 클라이언트가 호스트에서 사용 가능한 모든 인터페이스에서 응답할 수 있다.
어플리케이션에서 특별히 포트번호를 요청하지 않는다면 클라이언트는 임시의 포트번호를 커널이 선택하게 나둔다.
서버는 시작할때 잘 알려진 포트번호를 bind한다.
만약 서버가 bind를 하지 않으면, 커널은 소켓에 대한 일시적인 포트를 선택한다.
근데 이럴일은 별로 없음..
int listen(int 소켓 파일디스크립터, int 연결 요청 받을 개수);
이제 연결 요청이 들어오면 수락을 해야한다.
3-way handshake가 끝나면 accept를 받을 수 있다.
연결 요청을 받을 소켓을 생성한다.
즉 서버에서 생성한 소켓을 연결 요청을 받을 소켓으로 만든다
그럼 클라이언트의 active 소켓이 이 소켓에 연결을 요청해
이 서버의 연결요청 소켓이 연결을 받아들인다.
그럼 연결이 되면 클라이언트의 소켓을 이용해 통신을 한다
수락을 한다는 것은 클라이언트와 서버가 데이터를 주고받을 수 있는 상태임을 뜻한다.
즉 소켓이 필요하다.
accept 함수는 이 클라이언트와 통신을 할 수 있게해주는 소켓을 생성해준다.
complete connection 큐에서 대기 중인 클라이언트의 연결 요청을 수락하는 기능을 한다
호출 성공시 통신에 사용할 소켓을 생성하고 소켓의 파일디스크립터를 반환한다.
completed connection 큐의 소켓의 연결요청을 수락한다
=>수락해서 소켓 생성만약 completed queue가 비엇으면 process는 sleep status로 간다.
int accept(int 서버소켓의 파일 디스크립터,struct sockaddr* addr, socklen_t* addrlen);
-addr : 클라이언트의 소켓 주소 정보를 담을 구조체 주소
-addrlen : addr에 전달된 주소의 변수 크기, 단 크기를 sizeof()로 정한 후 주소로 넘긴다.
accept 함수는 서버와 클라이언트의 통신을 수락해주고 이에 사용할 소켓을 넘겨준다.
accept의 리턴값 = 클라이언트 소켓 디스크립터!! 실패하면 -1
accept을 하면 새로운 소켓이랑 연결이 된다.
기존 연결된 소켓도 여전히 연결이 유지된다.
이제 통신을 진행하면 된다.
그렇다면 클라이언트는 어떻게 진행이 될까?
서버와 차이점은 2. 연결 요청 bind 부분이다.
서버가 listen을 통해 연결 요청을 받을 수 있는 상태 이후, 클라이언트는 연결을 요청할 수 있다.
int connect(int sockfd, const struct sockaddr* servaddr,socklen_t addrlen);
함수 실행에 성공하면 리턴 0 실패하면 -1
connect는 생성된 소켓의 파일 디스크립터를 반환!
- connect함수가 실행되고 두가지 상황이 실행되어야 함수가 반환됨.
1. 서버에서 연결요청 접수(0)
2. 오류로 인한 연결 요청 중단(-1)
**연결 요청은 서버의 accept를 의미하는게 아니다. 서버에 연결 대기를 걸어 놓는 것임**
=> connect가 반환이 되어도 바로 연결이 되지 않을 수도 있다.
서버는 직접 소켓에 IP와 PORT를 할당하였다.
반면 클라이언트는 주소할당 과정이 없었다.
통신을 할때는 주소정보가 필수적이다, 그렇다면 언제 할당이 되지??
=> bind를 통해 소켓에 직접 당하지 않아도 자동으로 할당이 된다.
int close(int sockfd);
성공하면 0을 리턴하고 실패하면 -1을 리턴한다
close의 뜻
위의 과정으로 진행이 된다.
서버는 클라이언트가 connect을 하기 전 accept를 실행할 수 있다.
단 이때는 connect 요청이 올 때까지 accept를 호출한 위치에서 서버가 blocking 된다.
왜?? accept을 했는데 completed connection 큐에 아무것도 없으면 프로세스가 sleep 되니깐 서버가 block댐
read와 write의 호출을 통해 데이터를 전송하는 경우 호출 시기에 따라 전송이 된다고 가정할 수 있다.
TCP는 버퍼를 사용해 한번에 전송을 한다고 했다. 그렇다면 하나의 데이터에 write를 여러번 호출한 데이터들, 즉 섞인 데이터가 있다면 어떻게 될까?
서버와 클라이언트가 송수신을 하다가 한 쪽의 소켓이 죽으면 나머지 쪽에서의 read 함수의 반환 값은 0이 된다,
그래서 서버에서 연결이 끊어짐을 감지하려면
read함수의 반환 값이 0임을 처리하면 된다.
서버라..
제가 프라하에서
파스타 서빙을 하던 그 때가 기억나네요..