CS - 네트워크(2) TCP/IP의 데이터를 전기신호로

김영현·2023년 7월 17일
0

CS

목록 보기
16/32

프로토콜 스택의 내부

프로토콜은 스택은 OS단에서 지원하는 네트워크 제어용 소프트웨어라고 보면 된다
어떠한 애플리케이션에서 송신까지의 과정은 이렇다.

1.애플리케이션에서 socket에 요청(리졸버)
2.socket프로토콜 스택에 요청
3.프로토콜 스택(TCP,UDP,IP)에서 랜 드라이버로.
4.랜 드라이버에서 랜 어댑터(랜카드)로.

프로토콜 스택엔 TCP와 UDP로 데이터 송수신을 함.
이도 하나의 프로토콜임.

  • TCP : 일반적인 애플리케이션 데이터 송수신 할때.
  • UDP : DNS 서버 조회짧은 데이터송수신 할때.

패킷을 통신 상대까지 운반하는데 IP가 쓰임.
IP는 2가지로 이루어짐.

  • ICMP : 패킷 운반시 발생하는 오류 통지
  • ARP : IP주소에 대응하는 MAC주소를 조사할 때 쓰임

소켓의 실체

소켓은 개념적인 것. 실제로 존재하는 건 아님(추상화 했따는 거겠지)
소켓의 다양한 정보들(IP, 포트번호, 웹서버 주소 등...)은 메모리에 저장됨.
프로토콜 스택은 결국 소켓의 정보를 기반으로 데이터를 송수신함.

서버에 접속하다.

소켓이 작성되면 애플리케이션은 connect를 호출한다. 그러면 프로토콜 스택은 자신의 소켓을 서버측 소켓에 접속함.
여기서 접속이란, 통신 상대와 제어 정보를 주고받아 소켓에 정보를 기록, 데이터를 송수신 가능한 상태로 만드는 것이다.
예를들어 클라이언트측이 제 아이피는 aaa.bbb.ccc 구요. 포트번호는 yyyy입니다!라고 하는것이다.
데이터 송수신동작을 실행할땐 일시적으로 송수신 하는 데이터를 보관해야함. 이를 버퍼 메모리 라고한다.
=> 주기억장치와 I/O사이에 쓰는 그 버퍼메모리와 의미가 일치함.

접속 동작의 실체

위에서 말한 제어 정보TCP의 헤더에 담긴다. 여기엔 중요한 정보들이 있는데

  1. 송신처, 수신처 포트번호.
  2. 컨트롤 비트.
    등... 다양한 정보들이 있다. 외울 필요는 없지만, SYN과 ACK는 알아야함

접속, 송-수신, 연결 끊기. 이런 과정 속에서도 모두 TCP 헤더에 제어정보를 담아 보냄.
또한, IP 에도 제어정보가 있다. 따라서 데이터가 패킷화되어 송수신 하면 이런 그림이 된다.
[[이더넷,IP 제어정보], [TCP 제어정보], [데이터]]
=> 데이터앞에 TCP 제어정보가 들어오고, IP,이더넷 제어정보가 들어온다. 상대측은 반대로 읽는다.

connect(<디스크립터>, <서버측 Ip주소와 포트번호>, ...)를 호출하면.

  1. 명령이 프로토콜 스택 TCP부분에 전달.
  2. 데이터 송-수신 동작 개시를 나타내는 헤더제작.
    2-1. SYN이라는 비트를 1로 만든다(접속 한다는 의미)
  3. IP에 건네주어, 송신하도록 의뢰. 그러면 IP담당 부분이 패킷 송신동작 시행.
  4. 서버가 잘 받았으면 SYN, ACK비트를 1로 만들어 클라이언트에게 응답.
  5. 클라이언트도 역시 잘 받았으면 ACK비트를 1로만들어 서버에 반송.

=> 이게 바로 3-way handshake

프로토콜 스택에 Http메시지를 넘겨보자

애플리케이션connect()에서 제어권이 넘어왔다면, 이제 데이터를 write()로 보낼 차례다.
여기서 주의할 점은 프로토콜 스택은 데이터에 무슨내용이 쓰여있는지 모른다. 일정한 길이의 바이너리 데이터라는 것만 알 뿐.

프로토콜 스택송신 데이터를 받아서 처리하는 과정

  1. 일단 버퍼 메모리에저장한다. 바로바로 보내면, 네트워크의 효율이 저하됨. 따라서 MTU라는 패킷의 규격대로 보냄.
    또한, 정해놓은 시간이 지나면 그대로 보낸다. 단, 대화형 애플리케이션은 지연시간이 있으면 안되므로 버퍼 메모리를 거치지 않고 바로 송신하는 경우가 있음.
  • MTU : 한 패킷에 저장할 수 있는 데이터의 최대 크기. 보통 1500byte. 패킷에는 보통 헤더가 들어있기에, 헤더를 뺀 실제 데이터 크기를 MSS라고함
  1. 데이터가 크면, 잘게잘게 쪼갠다.
    form같은데서 post로 넘겨주는 데이터는 대게 MSS규격을 초과함. 따라서 송신버퍼의 데이터를 규격대로 잘라서 송신함.

  2. ACK Number을 사용하여 패킷이 도착했는지 확인.
    데이터를 잘게 쪼갰다면, 순서를 알아야함. 이때문에 송신측에서 시퀀스 번호TCP 헤더에 담아 보냄.
    이렇게 시퀀스 번호를 담아 보내고, 서버측에서 잘 받았음을 응답하는 것이 ACK Number.
    시퀀스 번호를 계속 더한 값을 응답해준다.(당연히 ACK비트도 1로 만들어 넘겨줌).
    클라이언트는 ACK Number를 받아 다음 요청때 시퀀스 번호로 보냄.
    시퀀스 번호는 난수이기에, 접속 동작에서 클라이언트가 SYN비트를 1로 만들어 보낼때, 초기 시퀀스 번호값도 보냄. 서버측에선 클라이언트 시퀀스 번호를 토대로 계산한 ACK Number + 서버측 시퀀스 번호를 응답함.

  • 시퀀스 번호 : 다음 패킷이 몇번째 바이트부터 시작하는지 나타내는 번호.
    예를 들어 첫번째 패킷의 크기가 1400바이트. 그렇다면 다음 시퀀스 번호는 원래 시퀀스 번호+1400임.
  1. 상대가 데이터를 받았다고 할 때까지 송신 버퍼에 데이터 보관. ACK Number가 수신되지 않으면, 패킷 재 송신.
    단, 물리적으로 연결이 끊겼다면 재송신x(넽워크 불안정...).
    기다리는 시간을 타임아웃이라 함. 기다리는 시간은 ACK Number가 돌아오는 시간에 따라 유동적으로 변함.

  2. 윈도우 제어방식으로 ACK Number를 관리함. 지금까지 설명한건 핑-퐁방식.
    하나의 요청, 처리, 응답 과정을 거침. 하지만 ACK Number가 돌아올때까지 가만히있으면 자원낭비다.
    ACK Number가 돌아오는 동안, 계속해서 패킷을 보냄. 이때 수신측 버퍼메모리의 용량은 한계가 있음.
    따라서 수신측송신측에게 수신 버퍼메모리용량을 알려줌(TCP 헤더의 윈도우 필드에 담아 보냄. 송신측은 이를 계산해서 데이터를 적절히 보냄.
    또한, 수신 가능한 데이터의 최댓값을 윈도우 사이즈(=수신측 버퍼메모리)라고 함.

  3. ACK Number윈도우 사이즈를 합승. 각각 따로보내는 건, 자원낭비. 통지 할때 같이 보낸다.
    왜냐면 윈도우 사이즈는 수신 버퍼가 비게 됐을때 알려주면됨. 그리고 ACK Number데이터를 정상적으로 수신했을 때 보내는 것. 따라서 애플리케이션에서 일어난 의뢰가 끝났을 때 윈도우사이즈+ACK Number를 같이 보내면 됨.
    ACK Number도 사실 수신한 데이터의 끝에서 한 번만 보내면 된다
    => 어차피 수신측은 송신측의 시퀀스 번호대로 패킷 순서를 보장함.

  4. HTTP 응답메시지를 수신함.
    브라우저가 소켓 라이브러리의 read()호출. 프로토콜 스택에 제어 넘어감.
    데이터 조각 TCP헤더 조사해서 문제 없으면 ACK Number 반송
    데이터 조각 수신버퍼에 보관
    수신 버퍼에 있는 데이터를 애플리케이션이 정한 메모리 영역에 할당.
    윈도우송신측에 통지. 이때 송신측은 서버겠지?

서버와의 연결 끊기

데이터 송수신이 끝났다면, 연결을 끊을 차례다. 정확히는 데이터 송신을 완료한 쪽에서.
즉, 서버측에서 close()를 호출한다.(클라이언트측에서도 가능). 아래는 일련의 과정임

  1. 서버측에서 TCP 헤더의 FIN 비트를 1로 바꾸고 송신
  2. 클라이언트측은 잘 받았다고 ACK Number를 반송. 그리곤 close()호출.
  3. 위의 1~2과정을 클라이언트-서버 만 바꿔서 진행.

만약 이 과정의 시작이 클라이언트측이라면, 마지막에 서버에서 ACK Number를 받지 못할 수 있음.
따라서 클라이언트측 소켓을 바로 말소한다면, 서버측에서 다시한번 FIN을 보낸다면 충돌이 일어남.
오동작을 막기위해 소켓을 즉시 말소하지 않고 일정시간 기다림. 이를 TIME_WAIT이라함.

profile
모르는 것을 모른다고 하기

0개의 댓글