어플리케이션 프로세스들끼리 소통하기 위해서는 TCP 소켓 혹은 UDP 소켓을 사용하여야한다.
socket을 생성할때 파라미터로 type을 선택할 수 있다(SOCK_STREAM / SOCK_DGRAM)
TCP Server
1. TCP socket을 연다. socket()
2. 원하는 포트에 바인딩 시킨다. bind()
3. 서버니까 listen 용도로 사용한다. listen()
4. 클라이언트로부터 요청을 받을 준비가 되어있다. accept()
여기까지 수행되면 서버는 클라이언트로 부터 요청을 받을 때까지 block 상태이다.
TCP Client
1. TCP socket을 연다. socket()
2. 원하는 서버와 연결된다. connect()
두 개의 TCP 소켓은 연결된다.
서버와 클라이언트는 read()
, write()
기능을 수행한다.
프로세스들은 segment단위로 패킷을 주고받으며 논리적인 관계를 맺는다.
대표적으로 TCP와 UDP가 있다.
segment = head + data
multiplexing
어플리케이션 계층으로부터 들어온 여러개의 소켓들을 모아서 하나의 segment로 만들어 네트워크 계층으로 전송한다.
Multiplexing at send host: gathering data from multiple sockets, enveloping data with header (later used for demultiplexing)
demultiplexing
segment의 head의 정보를 가지고 어떤 소켓으로 올려 보내야할지 판단한다.
Demultiplexing at rcv host: delivering received segments to correct socket
에러가 발생하면 올려보내지 않는다.
demultiplexing는 들어온 패킷이 TCP와 UDP 인지에 따라 Connectionless demultiplexing와 Connection-oriented demultiplexing으로 나뉜다.
TCP
데이터가 유실되지 않는 기능(reliable), 순서에 맞추어 데이터를 전달하는 기능 등을 제공한다.
하지만 네트워크 채널은 unreliable해서 패킷 에러가 발생하거나 패킷 유실이 발생할 수 있다. 따라서 TCP에서 reliable하게 데이터를 제공하기 위해서는 Reliable Data Transfer(RDT)를 생성하여야한다.
receiver host가 send host에게 피드백 패킷이 에러가 발생할 수도 있다. 피드백 에러가 발생하면 send host는 재전송한다.
receiver host는 중복되는 요청인지 확인하기 위해서 패킷의 header에 sequence number를 부여한다. sequence number는 최소화 해야한다.
⬆️ 위 예제에는 0,1 두개의 번호로 패킷을 식별할 수 있다. (처음에 0을 보내고 응답0을 받았으면 다음 번호인 1을 보냄, 응답0을 못받으면 다시 0보내고 서버는 0이 두번 왔으므로 같은 패킷인지 판단 가능)
정해진 타임 내에 요청/응답 결과가 가지 않으면 재전송한다.
-> 하나씩 보내기 때문에 성능이 좋지 않기에 실제로는 여러개를 한번에 보낸다.
UDP
multiplexing 기능과 에러 처리 기능을 제공한다.