Mac OS에서 C언어를 기반으로 하는 학습은 피곤하다.(읽는 책마다 Window + Visual Studio 기반이다.)
그래서 Docker로 Ubuntu를 올려서 학습해본다!
Linux에서는 file, socket을 다루는 API가 동일하다.
...
리눅스 기준 파일/소켓에 부여된 정수를 의미
0 : 표준입력 Standard Input
1 : 표준출력 Standard Output
2 : 표준에러 Standard Error
[0, 1, 2]는 이미 입력, 출력, 에러용으로 사용하는 중이다.
추가적으로 소켓이나 파일을 생성하고 descriptior를 얻으면 3부터 얻는다.
입력과 출력은 동시에 불가능하다.
송수신 소켓에는 내부적으로 버퍼가 존재한다.
1: 연결지향형 : 데이터가 소멸되지 않음을 보장받는다.
2: 데이터의 경계가 없음 : write 함수 3번으로 100메가를 보내면 read함수 1번으로 100메가를 수신할 수 있다. (버퍼의 데이터 read, write 호출 횟수가 크게 중요하지 않음)
3. 버퍼도 확인하면서 데이터를 전송함
1: 전송된 순서에 상관없이 가장 빠른 전송을 지향한다.
2: 데이터 손실 우려, 파손 우려
3: 전송되는 데이터의 경계가 존재 : 예로 2번 write하면 2번 read를 해야한다.
3: 한 번에 전송할 수 있는 데이터 크기가 존재
생성 -> 주소할당 -> 연결요청 대기상태 -> 연결허용 -> 데이터 송수신 -> 종료
socket() -> bind() -> listen() -> accept() -> read()/write() -> close()
listen()함수가 호출되어야 클라이언트가 연결요청을 할 수 있는 상태가 된다.
listen(int sock, int backlog)
sock : 대기상태에 두고자 하는 소켓의 파일 디스크립터
backlog : 연결요청 대기 큐의 크기정보, 5가 전달되면 클라이언트의 요청 5개까지 대기시킬 수 있음 (잦은 연결요청이 필요한 경우 더 큰 값이 필요)
클라이언트의 연결요청도 인터넷을 통해서 흘러 들어오는 데이터의 전송
Server Socket을 연결요청을 담을 Socket으로 사용한다.
이후 실제 데이터를 주고받을 때는 새로운 Socket을 하나 더 만들어
클라이언트와 자동으로 연결시켜 준다.
accept(int sock, struct socket addr, socklen_t addrlen)
sock : 대기상태에 두고자 하는 소켓의 파일 디스크립터
addr : 클라이언트의 주소정보를 담을 포인터
addrlen : 주소 크기를 담을 포인터
대기 큐가 찰 때까지, accept함수는 데이터 송수신 소켓의 파일 디스크립터를 반환하지 않고 blocking한다.
생성 -> 연결요청 -> 데이터 송수신 -> 연결종료
socket() -> connect() -> read()/write() -> close()
int connect(int sock, struct sockaddr * servaddr, socklen_t addrlen)
sock : 클라이언트 소켓의 파일 디스크립터
servaddr : 연결요청 할 서버의 주소정보 구조체 포인터
socklen_t : 주소의 변수 크기
Server Socket과정과의 차이점은 connect()이다.
소켓을 생성한 후 서버로 연결을 요청하는 과정이며 Server Socket이 listen()을 호출한 이후부터 연결요청을 성공할 수 있다.
Server Socket은 listen()을 호출해야 대기 큐를 만든다.
connect()함수가 호출되면 둘 중 한가지 상황이 된다.
1. 연결요청 접수완료 (accept 함수호출을 의미하는 것은 아니며 대기 큐에 등록된 것)
2. 연결요청 중단