TCPκ°€ 연결을 μƒμ„±ν•˜κ³  μ’…λ£Œν•˜λŠ” 방법, ν•Έλ“œμ‰μ΄ν¬

    TCPκ°€ 연결을 μƒμ„±ν•˜κ³  μ’…λ£Œν•˜λŠ” 방법, ν•Έλ“œμ‰μ΄ν¬


    μ €λ²ˆμ— μž‘μ„±ν–ˆλ˜ TCP의 ν—€λ”μ—λŠ” μ–΄λ–€ 정보듀이 λ‹΄κ²¨μžˆλŠ”κ±ΈκΉŒ? ν¬μŠ€νŒ…μ— 이어 μ΄λ²ˆμ—λŠ” TCP의 ν•Έλ“œμ‰μ΄ν¬ κ³Όμ •κ³Ό κ·Έ μ†μ—μ„œ λ³€ν™”ν•˜λŠ” TCP μƒνƒœμ— λŒ€ν•΄μ„œ ν•œλ²ˆ μ•Œμ•„λ³΄λ €κ³  ν•œλ‹€.

    TCPλŠ” μ‹ λ’°μ„±μžˆλŠ” 연결을 μΆ”κ΅¬ν•˜κΈ° λ•Œλ¬Έμ— 연결을 μƒμ„±ν•˜κ³  μ’…λ£Œν•˜λŠ” μˆœκ°„μ—λ„ λ‚˜λ¦„μ˜ μ‹ λ’°μ„± 확보λ₯Ό μœ„ν•΄ ν•Έλ“œμ‰μ΄ν¬(Handshake)라고 ν•˜λŠ” νŠΉλ³„ν•œ 과정을 거치게 λœλ‹€. TCPλ₯Ό μ‚¬μš©ν•˜μ—¬ 톡신을 ν•˜λŠ” 각 쒅단은 ν•Έλ“œμ‰μ΄ν¬ 과정을 톡해 μ–΄λ–€ TCP μ˜΅μ…˜λ“€μ„ μ‚¬μš©ν•  지, νŒ¨ν‚·μ˜ μˆœμ„œ 번호 동기화와 같이 톡신에 ν•„μš”ν•œ λͺ‡ 가지 정보λ₯Ό μ£Όκ³  λ°›λŠ”λ‹€.

    ν•˜μ§€λ§Œ 말둜만 μ„€λͺ…ν•˜λ©΄ μž¬λ―Έκ°€ μ—†μœΌλ‹ˆ, Cλ₯Ό μ‚¬μš©ν•˜μ—¬ 직접 κ°„λ‹¨ν•œ ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„λ₯Ό μž‘μ„±ν•΄λ³΄κ³  이 μΉœκ΅¬λ“€μ΄ ν•Έλ“œμ‰μ΄ν¬ κ³Όμ •μ—μ„œ μ£Όκ³  λ°›λŠ” νŒ¨ν‚·μ„ λͺ°λž˜ μ—Ώλ³Έ 결과물도 μ‘°κΈˆμ”© μ²¨λΆ€ν•˜λ €κ³  ν•œλ‹€.

    μ—°κ²° 지ν–₯의 μ˜λ―Έμ— λŒ€ν•΄μ„œ

    ν•Έλ“œμ‰μ΄ν¬λ₯Ό μ΄μ•ΌκΈ°ν•˜κΈ°μ— μ•žμ„œ, TCPκ°€ μƒμ„±ν•˜κ³  μ’…λ£Œν•˜λŠ” 연결에 λŒ€ν•œ 이야기λ₯Ό λ¨Όμ € ν•˜λ €κ³  ν•œλ‹€. μ•„λ§ˆ TCP에 λŒ€ν•΄μ„œ 곡뢀해보신 뢄듀은 TCP의 λŒ€ν‘œμ μΈ νŠΉμ§• 쀑 ν•˜λ‚˜μΈ μ—°κ²° 지ν–₯(Connection Oriented)μ΄λΌλŠ” ν‚€μ›Œλ“œμ— λŒ€ν•΄μ„œ λ“€μ–΄λ³΄μ•˜μ„ 것이닀.

    μ—°κ²° 지ν–₯은 말 κ·ΈλŒ€λ‘œ μ—°κ²°λ˜μ–΄ μžˆλŠ” μƒνƒœλ₯Ό 지ν–₯ν•œλ‹€λŠ” μ˜λ―Έμ΄λ‹€. 사싀 μ—°κ²°κ³Ό 비연결은 λ„€νŠΈμ›Œν¬λ₯Ό κ³΅λΆ€ν•˜λ‹€λ³΄λ©΄ μ—¬λŸ¬ 번 마주치게 λ˜λŠ” 단어인데, ν•„μžλŠ” 개인적으둜 이 λ‹¨μ–΄λ“€μ˜ μ˜λ―Έκ°€ 쑰금 ν—·κ°ˆλ Έμ—ˆλ‹€.

    μƒμ‹μ μœΌλ‘œ 두 κΈ°κΈ°κ°€ 톡신을 ν•˜λ €λ©΄ 케이블이든 뭐든 연결이 λ˜μ–΄μžˆμ–΄μ•Ό 할텐데, ꡳ이 μ™œ μ—°κ²° 지ν–₯κ³Ό λΉ„μ—°κ²° 지ν–₯을 λ‚˜λˆ„μ–΄ 놓은 것인지 이해가 λ˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ΄λ‹€.

    이게 ν—·κ°ˆλ¦¬λŠ” μ΄μœ λŠ” 물리적인 μ—°κ²°κ³Ό 논리적인 μ—°κ²°μ˜ 차이 λ•Œλ¬Έμ΄λ‹€.

    μš°λ¦¬κ°€ 일반적으둜 기기와 λ‹€λ₯Έ κΈ°κΈ°λ₯Ό μ—°κ²°ν–ˆλ‹€κ³  ν•  λ•Œ λ– μ˜¬λ¦¬λŠ” 생각은 컴퓨터와 λͺ¨λ‹ˆν„°λ₯Ό μ—°κ²°ν•˜κ±°λ‚˜, USB와 컴퓨터λ₯Ό μ—°κ²°ν•˜λŠ” λ“±μ˜ 상황이닀. 즉, κΈ°κΈ° κ°„μ˜ 물리적인 연결이닀.

    physical connection 케이블을 사용하여 두 개의 장치를 물리적으로 연결한다

    반면, μ—°κ²° 지ν–₯μ΄λΌλŠ” λ‹¨μ–΄μ—μ„œ μ‚¬μš©ν•˜κ³  μžˆλŠ” μ—°κ²°μ˜ μ˜λ―ΈλŠ” 논리적인 μ—°κ²°(Logical Connection)을 μ˜λ―Έν•œλ‹€. μ΄λ•Œ λ‹Ήμ—°νžˆ μ—¬λŸ¬ 개의 κΈ°κΈ°κ°€ μ„œλ‘œ 톡신을 ν•˜κΈ°μœ„ν•΄μ„œλŠ” 물리적인 μ—°κ²° λ˜ν•œ λ™λ°˜λ˜μ–΄μ•Όν•œλ‹€.

    logical connection

    쑰금 더 μ‰½κ²Œ μ΄μ•ΌκΈ°ν•΄λ³΄μžλ©΄, 두 κΈ°κΈ°κ°€ μ„œλ‘œ μ—°κ²°λ˜μ–΄ μžˆλŠ” μƒνƒœλ₯Ό μœ μ§€ν•˜λŠ” 것이닀.

    μ „ν™”λ₯Ό 예둜 λ“€μžλ©΄, μ „ν™”κ°€ 전화선에 μ—°κ²°λ˜μ–΄μžˆλŠ” 것이 물리적인 연결이고 μ‹€μ œλ‘œ λ‹€λ₯Έ 전화와 톡화λ₯Ό ν•˜κ³  μžˆλŠ” 상황이 논리적인 μ—°κ²°, 즉 μ—°κ²°λ˜μ–΄ μžˆλŠ” μƒνƒœμΈ 것이닀.

    κ·Έλ ‡λ‹€λ©΄ μ™œ TCPλŠ” 이런 μ—°κ²° μƒνƒœλ₯Ό μœ μ§€ν•˜λŠ” 걸까? κ·Έ μ΄μœ λŠ” κ°„λ‹¨ν•˜λ‹€. λ°”λ‘œ 연속적인 데이터 μ „μ†‘μ˜ 신뒰성을 μœ„ν•΄μ„œμ΄λ‹€.

    기본적으둜 TCPλŠ” νŒ¨ν‚· 전솑 방식을 μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— 보내렀고 ν•˜λŠ” 데이터λ₯Ό μ—¬λŸ¬ 개의 νŒ¨ν‚·μœΌλ‘œ μͺΌκ°œμ„œ 보낸닀. μ΄λ•Œ λ„€νŠΈμ›Œν¬λ₯Ό 톡해 λͺ¨λ“  데이터λ₯Ό ν•œλ²ˆμ— 팍! λ³΄λ‚΄λŠ” 것이 μ•„λ‹ˆλΌ 일정 λ‹¨μœ„λ‘œ λ¬Άμ–΄μ„œ 슀트림처럼 μƒλŒ€λ°©μ—κ²Œ ν˜λ €λ³΄λ‚΄κ²Œ λœλ‹€.

    그럼 ν•œλ²ˆ 데이터λ₯Ό λ°›λŠ” μˆ˜μ‹ μž μž…μž₯μ—μ„œ μƒκ°ν•΄λ³΄μž. νŒ¨ν‚· 전솑 λ°©μ‹μ˜ μž₯점 쀑 ν•˜λ‚˜λŠ” νšŒμ„ μ„ μ μœ ν•˜μ§€ μ•Šκ³  적은 μ–‘μ˜ νšŒμ„ μœΌλ‘œλ„ λ™μ‹œμ— 톡신을 ν•  수 μžˆλ‹€λŠ” 점이닀.

    κ·Έλ ‡λ‹€λŠ” 것은 각 쒅단이 λ™μ‹œλ‹€λ°œμ μœΌλ‘œ μ—¬λŸ¬ κΈ°κΈ°λ“€κ³Ό νŒ¨ν‚·μ„ μ£Όκ³  λ°›κ³  μžˆλ‹€λŠ” 의미인데, μ΄λ•Œ λˆ„κ°€ 보낸 λͺ‡ 번째 νŒ¨ν‚·μ΄λΌλŠ” 정보가 μ—†λ‹€λ©΄ μˆ˜μ‹  츑은 ꡉμž₯히 ν˜Όλž€μŠ€λŸ¬μšΈ 것이닀.

    pipes 연결 상태가 없는 패킷을 구분한다는 것은 한 양동이에 담긴 물을 구분하고 싶다는 말과 같다

    μœ„ κ·Έλ¦Όμ—μ„œ νŒŒμ΄ν”„λŠ” 물리적인 μ—°κ²°, 각 νŒŒμ΄ν”„ 끝의 ꡬ멍은 포트, μ–‘λ™μ΄λŠ” νŒ¨ν‚·μ„ μ²˜λ¦¬ν•  ν”„λ‘œμ„ΈμŠ€λΌκ³  μƒκ°ν•΄λ³΄μž. μ΄λ•Œ μ—°κ²° μƒνƒœμ— λŒ€ν•œ ꡬ뢄을 ν•˜μ§€ μ•Šκ³  νŒ¨ν‚·μ„ κ΅¬λΆ„ν•˜κ³  μ‹Άλ‹€λŠ” 것은 마치 ν•œ 양동이에 λ‹΄κΈ΄ λ¬Ό μ€‘μ—μ„œ μ–΄λ–€ ν•œ νŒŒμ΄ν”„ κ΅¬λ©μ—μ„œ λ‚˜μ˜¨ 물을 ꡬ뢄해내고 μ‹Άλ‹€λŠ” 말과 λΉ„μŠ·ν•˜λ‹€.

    κ·Έλ ‡κΈ° λ•Œλ¬Έμ— TCPλŠ” A와 B의 μ—°κ²° μƒνƒœ, A와 C의 μ—°κ²° μƒνƒœ λ“± 각 κΈ°κΈ°κ°„μ˜ μ—°κ²° μƒνƒœλ₯Ό λ”°λ‘œ κ΅¬λΆ„ν•˜κ³  μžˆλŠ” 것이닀. μ΄λ•Œ TCPλŠ” μƒλŒ€λ°©κ³Ό μ—°κ²° μƒνƒœλ₯Ό λ§Œλ“€κ±°λ‚˜ ν•΄μ œν•˜κΈ° μœ„ν•΄ νŠΉλ³„ν•œ 과정을 κ±°μΉ˜λŠ”λ°, 이 과정을 ν•Έλ“œμ‰μ΄ν¬(Handshake)라고 ν•œλ‹€.

    3 Way Handshake

    λ¨Όμ €, 연결을 λ§Œλ“œλŠ” κ³Όμ •λΆ€ν„° μ‚΄νŽ΄λ³΄λ„λ‘ ν•˜μž. 연결을 생성할 λ•Œ κ±°μΉ˜λŠ” ν•Έλ“œμ‰μ΄ν¬ 과정을 3 Way Handshake라고 ν•˜λŠ”λ°, 3 WayλΌλŠ” 말 κ·ΈλŒ€λ‘œ 총 3번의 톡신 과정을 κ±°μΉœλ‹€.

    이 과정을 κ±°μΉ˜λ©΄μ„œ 톡신을 ν•˜λŠ” μ–‘ 쒅단은 λ‚΄κ°€ λˆ„κ΅¬λž‘ ν†΅μ‹ ν•˜κ³  μžˆλŠ”μ§€, λ‚΄κ°€ λ°›μ•„μ•Όν•  λ°μ΄ν„°μ˜ μ‹œν€€μŠ€ λ²ˆν˜Έκ°€ λͺ‡ λ²ˆμΈμ§€μ™€ 같은 정보λ₯Ό μ£Όκ³  λ°›μœΌλ©΄μ„œ μ—°κ²° μƒνƒœλ₯Ό μƒμ„±ν•˜κ²Œ λœλ‹€.

    3way handshake

    μ΄λ•Œ μš”μ²­μž(Initiator)λŠ” μ—°κ²° 생성 μš”μ²­μ„ λ¨Όμ € 보낸 μͺ½, μˆ˜μ‹ μž(Receiver)λŠ” μ—°κ²° 생성 μš”μ²­μ„ 받은 μͺ½μ„ μ˜λ―Έν•œλ‹€. μ΄λ ‡κ²Œ ν‘œν˜„ν•˜λŠ” μ΄μœ λŠ” 일반적으둜 μš°λ¦¬κ°€ μƒκ°ν•˜λŠ” ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„, λ‘˜ 쀑에 μ–΄λŠ μͺ½μ΄λ“  자유둭게 λ¨Όμ € μ—°κ²° 생성 μš”μ²­μ„ 보낼 수 있기 λ•Œλ¬Έμ΄λ‹€.

    그럼 ν•œ 번 각각의 μƒνƒœκ°€ μ–΄λ–€ 것을 μ˜λ―Έν•˜λŠ”μ§€, 두 κΈ°κΈ°κ°€ μ„œλ‘œ μ£Όκ³  λ°›κ³  μžˆλŠ” SYNκ³Ό ACKλŠ” 무엇을 μ˜λ―Έν•˜λŠ”μ§€ μ‚΄νŽ΄λ³΄λ„λ‘ ν•˜μž.

    CLOSED

    3way closed

    아직 μ—°κ²° μš”μ²­μ„ μ‹œμž‘ν•˜μ§€ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— μ•„λ¬΄λŸ° 연결도 μ—†λŠ” μƒνƒœμ΄λ‹€.

    LISTEN

    3way listen

    μˆ˜μ‹ μžκ°€ μš”μ²­μžμ˜ μ—°κ²° μš”μ²­μ„ 기닀리고 μžˆλŠ” μƒνƒœμ΄λ‹€.

    이후 μš”μ²­μžκ°€ μ—°κ²° μš”μ²­μ„ 보내기 μ „κΉŒμ§€ μˆ˜μ‹ μžλŠ” 계속 이 μƒνƒœλ‘œ λŒ€κΈ°ν•˜κ²Œ λœλ‹€. 즉, 적극적으둜 μƒλŒ€λ°©μ—κ²Œ λŒ€μ‹œν•˜μ§€ μ•ŠλŠ”λ‹€λŠ” 것인데, κ·Έλž˜μ„œ 이 μƒνƒœλ₯Ό μˆ˜λ™ 개방(Passive Open)이라 ν•˜κ³ , μˆ˜μ‹ μžλ₯Ό Passive Opener라고도 ν•œλ‹€.

    μ†ŒμΌ“ ν”„λ‘œκ·Έλž˜λ°μ„ ν•  λ•Œ, μ†ŒμΌ“ 바인딩을 ν•œ ν›„ listen ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κ²Œ 되면 μˆ˜μ‹ μžκ°€ LISTEN μƒνƒœλ‘œ λ“€μ–΄κ°€κ²Œ λœλ‹€.

    if ((listen(sockfd, 5)) != 0) {
      printf("Listen failed...\n");
      exit(0);
    }
    else {
      printf("Server listening..\n");
    }

    이후 μˆ˜μ‹ μžλŠ” μš”μ²­μžμ˜ μ—°κ²° μš”μ²­μ΄ ν™•μΈλ˜λ©΄ accept ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ λ‹€μŒ λ‹¨κ³„λ‘œ λ„˜μ–΄κ°€κ²Œ λœλ‹€.

    SYN_SENT

    3way synsent

    μš”μ²­μžκ°€ μˆ˜μ‹ μžμ—κ²Œ μ—°κ²° μš”μ²­μ„ ν•˜λ©΄μ„œ λžœλ€ν•œ 숫자인 μ‹œν€€μŠ€ 번호λ₯Ό μƒμ„±ν•΄μ„œ SYN νŒ¨ν‚·μ— λ‹΄μ•„ 보낸 μƒνƒœμ΄λ‹€. 이제 μš”μ²­μžμ™€ μˆ˜μ‹ μžλŠ” 이 μ‹œν€€μŠ€ 번호λ₯Ό μ‚¬μš©ν•˜μ—¬ 계속 μƒˆλ‘œμš΄ 값을 λ§Œλ“€κ³  μ„œλ‘œ ν™•μΈν•˜λ©° μ—°κ²° μƒνƒœμ™€ νŒ¨ν‚·μ˜ μˆœμ„œλ₯Ό ν™•μΈν•˜κ²Œ λœλ‹€.

    localhost.initiator > localhost.receiver: Flags [S], seq 3414207244, win 65535

    TCP μ„Έκ·Έλ¨ΌνŠΈλ₯Ό 캑쳐할 수 μžˆλŠ” tcpdump μœ ν‹Έλ¦¬ν‹°λ‘œ 이 과정을 확인해보면 μš”μ²­μžκ°€ νŒ¨ν‚·μ˜ ν”Œλž˜κ·Έλ₯Ό SYN νŒ¨ν‚·μ„ μ˜λ―Έν•˜λŠ” S둜 μ„€μ •ν•˜κ³  μ‹œν€€μŠ€ 번호둜 3414207244λΌλŠ” 값을 μƒμ„±ν•΄μ„œ μˆ˜μ‹ μžμ—κ²Œ 보내고 μžˆμŒμ„ μ•Œ 수 μžˆλ‹€.

    이 κ²½μš°λŠ” μš”μ²­μžκ°€ μˆ˜μ‹ μžμ—κ²Œ 연결을 μƒμ„±ν•˜μžκ³  적극적으둜 λŒ€μ‹œν•˜λŠ” μƒν™©μ΄λ―€λ‘œ 이 μƒνƒœλ₯Ό λŠ₯동 개방(Active Open)이라고 ν•˜κ³ , μš”μ²­μžλ₯Ό Active Opener라고도 ν•œλ‹€.

    SYN_RECV

    3way synrecv

    SYN_RECVλŠ” μš”μ²­μžκ°€ 보낸 SYN νŒ¨ν‚·μ„ μˆ˜μ‹ μžκ°€ μ œλŒ€λ‘œ 받은 μƒνƒœλ₯Ό μ˜λ―Έν•œλ‹€.

    이후 μˆ˜μ‹ μžλŠ” μ œλŒ€λ‘œ 된 μ‹œν€€μŠ€ 번호λ₯Ό λ°›μ•˜λ‹€λŠ” ν™•μΈμ˜ 의미인 승인 번호(Acknowledgement) 값을 λ§Œλ“€μ–΄μ„œ λ‹€μ‹œ μš”μ²­μžμ—κ²Œ λŒλ €μ€˜μ•Όν•œλ‹€. μ΄λ•Œ 승인 λ²ˆν˜ΈλŠ” 처음 μš”μ²­μžκ°€ 보낸 μ‹œν€€μŠ€ 번호 + 1이 λœλ‹€.

    이 승인 번호 λ§Œλ“œλŠ” 과정은 μ–΄λ ΅κ²Œ 생각할 ν•„μš”κ°€ μ—†λŠ”κ²Œ, μ €λ²ˆ ν¬μŠ€νŒ…μ—μ„œ μ΄μ•ΌκΈ°ν–ˆλ“―μ΄ TCPλ₯Ό μ‚¬μš©ν•˜μ—¬ μ‹€μ œλ‘œ 데이터λ₯Ό μ£Όκ³  받을 λ•Œμ—λŠ” μƒλŒ€λ°©μ΄ 보낸 μ‹œν€€μŠ€ 번호 + μƒλŒ€λ°©μ΄ 보낸 λ°μ΄ν„°μ˜ byteλ₯Ό ν•©μ³μ„œ 승인 번호λ₯Ό λ§Œλ“€μ–΄λ‚Έλ‹€. 즉, λ‚΄κ°€ μ—¬κΈ°κΉŒμ§€ λ°›μ•˜μœΌλ‹ˆ, λ‹€μŒμ—λŠ” μ—¬κΈ°λΆ€ν„° λ³΄λ‚΄λ‹¬λΌλŠ” μΌμ’…μ˜ λ§ˆν‚ΉμΈ 것이닀.

    κ·ΈλŸ¬λ‚˜ 이런 ν•Έλ“œμ‰μ΄ν¬ κ³Όμ •μ—μ„œλŠ” 아직 데이터λ₯Ό μ£Όκ³  받지 μ•ŠκΈ° λ•Œλ¬Έμ— μ‹œν€€μŠ€ λ²ˆν˜Έμ— λ”ν• κ²Œ μ—†λ‹€. κ·Έλ ‡λ‹€κ³ ν•΄μ„œ μ‹œν€€μŠ€ 번호λ₯Ό 같은 번호둜 μ£Όκ³  λ°›μžλ‹ˆ νŒ¨ν‚·μ˜ μˆœμ„œλ₯Ό ꡬ뢄할 수 없지 μ•Šμ€κ°€? κ·Έλž˜μ„œ κ·Έλƒ₯ 1을 λ”ν•˜λŠ” 것이닀.

    방금 μ „κ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ tcpdump μœ ν‹Έλ¦¬ν‹°λ₯Ό μ‚¬μš©ν•˜μ—¬ 이 과정을 확인해볼 수 μžˆλ‹€.

    localhost.receiver > localhost.initiator: Flags [S.], seq 435597555, ack 3414207245, win 65535

    μˆ˜μ‹ μžκ°€ μš”μ²­μžμ—κ²Œ λ³΄λ‚΄λŠ” νŒ¨ν‚·μ„ μΊ‘μ²˜ν•΄λ³΄μ•˜λ”λ‹ˆ νŒ¨ν‚·μ˜ ν”Œλž˜κ·Έκ°€ S.둜 μ„€μ •λ˜μ–΄μžˆλ‹€. μ΄λ•Œ .κ°€ μ˜λ―Έν•˜λŠ” 것은 ν—€λ”μ˜ ACK ν”Œλž˜κ·Έ ν•„λ“œκ°€ 1μ΄λΌλŠ” κ²ƒμ΄λ―€λ‘œ 이 νŒ¨ν‚·μ—λŠ” μœ νš¨ν•œ 승인 λ²ˆν˜Έκ°€ λ‹΄κ²¨μžˆμŒμ„ μ•Œ 수 μžˆλ‹€.

    μˆ˜μ‹ μžλŠ” 이번 톡신을 톡해 μš”μ²­μžμ—κ²Œ 3414207245 μ΄λΌλŠ” 승인 번호λ₯Ό μ „λ‹¬ν•˜κ³  μžˆλŠ”λ°, 이 값은 방금 μ „ μš”μ²­μžκ°€ λ³΄λƒˆλ˜ μ‹œν€€μŠ€ 번호인 3414207244에 1을 λ”ν•œ 값이닀.

    λ˜ν•œ λžœλ€ν•œ 수둜 μžμ‹ μ˜ μ‹œν€€μŠ€ 번호인 435597555λ₯Ό λ‹€μ‹œ μƒμ„±ν•˜μ—¬ ν•¨κ»˜ μš”μ²­μžμ—κ²Œ 보내주고 μžˆλŠ” 것을 확인할 수 μžˆλ‹€.

    ESTABLISHED(μš”μ²­μž)

    3way established client

    μš”μ²­μžλŠ” μžμ‹ μ΄ 맨 μ²˜μŒμ— λ³΄λƒˆλ˜ μ‹œν€€μŠ€ λ²ˆν˜Έμ™€ μˆ˜μ‹ μžκ°€ μ‘λ‹΅μœΌλ‘œ 보내쀀 승인 번호, 즉 λ‚΄ μ‹œν€€μŠ€ 번호 + 1λ₯Ό μ‚¬μš©ν•˜μ—¬ 연결이 μ œλŒ€λ‘œ μ„±λ¦½λ˜μ—ˆλŠ”μ§€ 확인할 수 μžˆλ‹€. μžμ‹ μ΄ λ³΄λƒˆλ˜ μ‹œν€€μŠ€ λ²ˆν˜Έμ™€ μ΄λ²ˆμ— 받은 승인 번호의 μ°¨κ°€ 1이라면 μ œλŒ€λ‘œ 연결이 λ˜μ—ˆλ‹€κ³  νŒλ‹¨ν•˜λŠ” 것이닀.

    이후 μš”μ²­μžλŠ” 연결이 μ„±λ¦½λ˜μ—ˆλ‹€κ³  νŒλ‹¨ν•˜κ³  ESTABLISHED μƒνƒœλ‘œ λ“€μ–΄κ°€λ©΄μ„œ, μ΄λ²ˆμ—λŠ” μˆ˜μ‹ μžκ°€ μƒˆλ‘­κ²Œ λ§Œλ“€μ–΄μ„œ λ³΄λ‚΄μ€¬λ˜ μ‹œν€€μŠ€ λ²ˆν˜Έμ— 1을 λ”ν•œ 값을 λ‹€μ‹œ 승인 번호둜 μ‚¬μš©ν•˜μ—¬ λ‹€μ‹œ μˆ˜μ‹ μžμ—κ²Œ 보내쀀닀.

    즉, λ§ˆμ§€λ§‰μœΌλ‘œ μˆ˜μ‹ μžκ°€ λ³΄λ‚΄μ€¬λ˜ μ‹œν€€μŠ€ 번호인 435597555에 1을 λ”ν•œ 값인 435597556이 μš”μ²­μžμ˜ 승인 λ²ˆν˜Έκ°€ 될 κ²ƒμ΄λ‹€β€¦λ§Œ tcpdump의 λ™μž‘μ€ ν•„μžμ˜ μ˜ˆμƒκ³Ό λ‹¬λžλ‹€.

    localhost.initiator > localhost.receiver: Flags [.], ack 1, win 6379
    why 왜 1이 거기서 나와...?

    μ›λž˜λŒ€λ‘œλΌλ©΄ 435597556이 λ˜μ–΄μ•Όν•  μš”μ²­μžμ˜ λ§ˆμ§€λ§‰ 승인 λ²ˆν˜Έκ°€ λœ¬κΈˆμ—†μ΄ 1이 λ˜μ—ˆλ‹€. (μ²˜μŒμ—” 진심 λ‹Ήν™©ν–ˆλ‹€)

    사싀 이건 TCP의 자체 λ™μž‘μ€ μ•„λ‹ˆκ³  tcpdumpκ°€ μ œκ³΅ν•˜λŠ” κΈ°λŠ₯이닀. tcpdumpκ°€ νŒ¨ν‚·λ“€μ˜ μ‹œν€€μŠ€ 번호λ₯Ό μ•Œμ•„λ³΄κΈ° μ‰½κ²Œλ” μƒλŒ€μ μΈ μœ„μΉ˜λ‘œ μ•Œλ €μ£ΌκΈ° λ•Œλ¬Έμ΄λ‹€. 이후 이 두 쒅단이 μ£Όκ³  λ°›λŠ” 데이터λ₯Ό tcpdump둜 μΊ‘μ²˜ν•΄λ³΄λ©΄ 이게 무슨 말인지 쑰금 더 μ‰½κ²Œ μ•Œ 수 μžˆλ‹€.

    localhost.initiator > localhost.receiver: Flags [P.], seq 1:81, ack 1, win 6379, length 80: HTTP

    μ›λž˜λŒ€λ‘œλΌλ©΄ μš”μ²­μžκ°€ λ§ˆμ§€λ§‰μœΌλ‘œ λ³΄λ‚΄λŠ” 승인 λ²ˆν˜ΈλŠ” 435597556이 될 것이기 λ•Œλ¬Έμ— 첫 번째둜 μ „μ†‘ν•˜λŠ” λ°μ΄ν„°μ˜ μ‹œν€€μŠ€ 번호의 λ²”μœ„ λ˜ν•œ 435597556:435597637둜 좜λ ₯λ˜μ–΄μ•Όν•œλ‹€.

    κ·ΈλŸ¬λ‚˜ 인간이 μ΄λ ‡κ²Œ 큰 숫자λ₯Ό 계속 λ³΄λ©΄μ„œ λΆ„μ„ν•˜κΈ°λŠ” 쉽지 μ•ŠκΈ° λ•Œλ¬Έμ— 승인 번호λ₯Ό 1둜 보여주고, 이후 μ£Όκ³ λ°›λŠ” 첫 번째 μ‹œν€€μŠ€ 번호λ₯Ό 1λΆ€ν„° μ‹œμž‘ν•΄μ„œ μ•Œμ•„λ³΄κΈ° μ‰½κ²Œ λ§Œλ“€μ–΄μ£ΌλŠ” 것이닀. ν™•μ‹€νžˆ 435597556:435597637λ³΄λ‹€λŠ” 1:81이 μ•Œμ•„λ³΄κΈ° 쉽닀.

    ν•˜μ§€λ§Œ 이건 인간이 μ•Œμ•„λ³΄κΈ° μ‰½κ²Œ tcpdumpκ°€ μΉœμ ˆν•¨μ„ λ² ν‘Ό 것일뿐 μ‹€μ œλ‘œ 값이 1둜 λ³€κ²½λœ 것은 μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— tcpdump의 -S μ˜΅μ…˜μ„ μ‚¬μš©ν•˜μ—¬ 이 κΈ°λŠ₯을 λΉ„ν™œμ„±ν™”ν•˜λ©΄ μ›λž˜ 승인 λ²ˆν˜Έμ™€ μ‹œν€€μŠ€ 번호λ₯Ό κ·ΈλŒ€λ‘œ 좜λ ₯ν•  μˆ˜λ„ μžˆλ‹€.

    $ sudo tcpdump -S
    localhost.initiator > localhost.receiver: Flags [.], ack 435597556, win 6379

    ESTABLISHED(μˆ˜μ‹ μž)

    3way established server

    μš”μ²­μžμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ μˆ˜μ‹ μž λ˜ν•œ μžμ‹ μ΄ λ³΄λƒˆλ˜ μ‹œν€€μŠ€ λ²ˆν˜Έμ™€ μ΄λ²ˆμ— 받은 승인 번호의 μ°¨κ°€ 1이라면 μ œλŒ€λ‘œ 연결이 λ˜μ—ˆλ‹€κ³  νŒλ‹¨ν•˜κ³  ESTABLISHED μƒνƒœλ‘œ λ“€μ–΄κ°€κ²Œλœλ‹€. μ—¬κΈ°κΉŒμ§€ 였면 μš”μ²­μžμ™€ μˆ˜μ‹ μžλŠ” μ•ˆμ „ν•˜κ³  μ‹ λ’°μ„±μžˆλŠ” 연결이 μƒμ„±λ˜μ—ˆλ‹€κ³  νŒλ‹¨ν•˜κ³  본격적인 톡신을 μ‹œμž‘ν•  수 μžˆλ‹€.

    4 Way Handshake

    연결을 생성할 λ•Œμ™€ λ§ˆμ°¬κ°€μ§€λ‘œ, 연결을 μ’…λ£Œν•  λ•Œλ„ νŠΉμ •ν•œ 과정을 κ±°μ³μ„œ 연결을 μ’…λ£Œν•΄μ•Όν•œλ‹€.

    κ·Έλƒ₯ 연결을 λŠμ–΄λ²„λ¦¬λ©΄ μ•ˆλ˜λƒκ³  ν•  μˆ˜λ„ μžˆμ§€λ§Œ, ν•œ μͺ½μ—μ„œ 일방적으둜 연결을 λŠμ–΄λ²„λ¦¬λ©΄ λ‹€λ₯Έ ν•œ μͺ½μ€ 연결이 λŠμ–΄μ‘ŒλŠ”μ§€ μ§€μ†λ˜κ³  μžˆλŠ”μ§€ μ•Œ 방법이 μ—†λ‹€.

    λ˜ν•œ 연결을 μ’…λ£Œν•˜κΈ° 전에 아직 λ‹€ μ²˜λ¦¬ν•˜μ§€ λͺ»ν•œ 데이터가 μžˆμ„ μˆ˜λ„ 있기 λ•Œλ¬Έμ— μ–‘ μͺ½μ΄ λ‹€ μ •μƒμ μœΌλ‘œ 연결을 μ’…λ£Œν•  μ€€λΉ„κ°€ λ˜μ—ˆλŠ” 지λ₯Ό ν™•μΈν•˜λŠ” 과정이 ν•„μš”ν•œ 것이닀.

    μ΄λ•Œ μš”μ²­μžμ™€ μˆ˜μ‹ μžκ°€ 총 4번의 톡신 과정을 거치기 λ•Œλ¬Έμ—, 이 과정을 4 Way Handshake라고 λΆ€λ₯Έλ‹€.

    4way handshake

    μ΄λ²ˆμ—λ„ μš”μ²­μž(Initiator)와 μˆ˜μ‹ μž(Receiver)λΌλŠ” μš©μ–΄λ₯Ό μ‚¬μš©ν•˜κ³  μžˆλŠ”λ°, 3 Way Handshake와 λ§ˆμ°¬κ°€μ§€λ‘œ ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„, λ‘˜ 쀑에 μ–΄λŠ μͺ½μ΄λ“  μ—°κ²° μ’…λ£Œ μš”μ²­μ„ μ‹œμž‘ν•  수 있기 λ•Œλ¬Έμ— 이런 μš©μ–΄λ₯Ό μ‚¬μš©ν•˜λŠ” 것이닀.

    λ¨Όμ € μ—°κ²° 생성 μš”μ²­μ„ ν–ˆλ˜ μͺ½μ΄ λ¨Όμ € μ—°κ²° μ’…λ£Œ μš”μ²­μ„ 보낼 μˆ˜λ„ 있고, λ°˜λŒ€λ‘œ μ²˜μŒμ—λŠ” μ—°κ²° 생성 μš”μ²­μ„ λ‹Ήν–ˆλ˜ μͺ½μ΄ μ΄λ²ˆμ—λŠ” λ¨Όμ € μ—°κ²° μ’…λ£Œ μš”μ²­μ„ 보낼 μˆ˜λ„ μžˆλ‹€.

    사싀 κ°œλ°œμžλ“€μ€ 3 Way Handshake보닀 연결을 μ’…λ£Œν•˜λŠ” 과정인 4 Way Handshake에 더 μ˜ˆλ―Όν•˜κ²Œ λ°˜μ‘ν•  수 밖에 μ—†λŠ”λ°, 연결을 μƒμ„±ν•˜λŠ” κ³Όμ •μ—μ„œ λ¬Έμ œκ°€ λ°œμƒν•˜μ—¬ 연결이 μƒμ„±λ˜μ§€ μ•ŠλŠ”λ‹€λ©΄ λ‹€μ‹œ μ‹œλ„ν•˜λ©΄ κ·Έλ§Œμ΄μ§€λ§Œ, 이미 μƒμ„±λœ 연결을 μ’…λ£Œν•˜λŠ” 과정인 4 Way Handshakeμ—μ„œ λ¬Έμ œκ°€ λ°œμƒν•˜λ©΄ κ·ΈλŒ€λ‘œ 연결이 λ‚¨μ•„μžˆκΈ° λ•Œλ¬Έμ΄λ‹€.

    κ²Œλ‹€κ°€ 4 Way HandshakeλŠ” 3 Way Handshake처럼 순차적으둜 μ£Όκ³ λ°›λŠ” 방식이 μ•„λ‹ˆλΌ μƒλŒ€λ°©μ΄ 응닡을 쀄 λ•ŒκΉŒμ§€ λŒ€κΈ°ν•˜λŠ” 과정이 ν¬ν•¨λ˜μ–΄μžˆκΈ° λ•Œλ¬Έμ— 쀑간에 뭐 ν•˜λ‚˜ μ—‡λ‚˜κ°€λ©΄ μ„œλ‘œ 계속 λŒ€κΈ°λ§Œ ν•˜κ³  μžˆλŠ” λ°λ“œλ½(Deadlock) 상황이 μ—°μΆœλ  μˆ˜λ„ μžˆλ‹€.

    λ¬Όλ‘  쑰건에 따라 일정 μ‹œκ°„μ΄ μ§€λ‚˜λ©΄ νƒ€μž„μ•„μ›ƒμ΄ 되며 연결을 κ°•μ œλ‘œ μ’…λ£Œν•˜κ±°λ‚˜ λ‹€μŒ λ‹¨κ³„λ‘œ λ„˜μ–΄κ°ˆ μˆ˜λ„ μžˆμ§€λ§Œ κ·Έλž˜λ„ κ·Έ μ‹œκ°„ λ™μ•ˆ ν”„λ‘œμ„ΈμŠ€κ°€ λ©”λͺ¨λ¦¬μ™€ 포트λ₯Ό μ μœ ν•˜κ³  μžˆμœΌλ―€λ‘œ νŠΈλž˜ν”½μ΄ λ§Žμ€ μ„œλ²„λΌλ©΄ 이둜 인해 병λͺ©μ΄ λ°œμƒν•  κ°€λŠ₯성은 늘 μžˆλ‹€.

    FIN_WAIT_1

    4way finwait1

    λ¨Όμ € 연결을 μ’…λ£Œν•˜κ³ μž ν•˜λŠ” μš”μ²­μžκ°€ FIN νŒ¨ν‚·μ„ μƒλŒ€λ°©μ—κ²Œ λ³΄λ‚΄λ©΄μ„œ FIN_WAIT1 μƒνƒœλ‘œ λ“€μ–΄μ„œκ²Œ λœλ‹€.

    μ΄λ•Œ FIN νŒ¨ν‚·μ—λ„ μ‹œν€€μŠ€ λ²ˆν˜Έκ°€ ν¬ν•¨λ˜μ–΄μžˆκΈ΄ν•œλ°, μ΄λ²ˆμ—λŠ” λžœλ€ν•œ κ°’μœΌλ‘œ μƒμ„±ν•΄μ„œ λ³΄λ‚΄λŠ” 것이 μ•„λ‹ˆλ‹€. 3 Way HandshakeλŠ” μ‹œν€€μŠ€ λ²ˆν˜Έκ°€ μ—†λŠ” μƒν™©μ—μ„œ μƒˆλ‘œ λ§Œλ“€μ–΄μ•Όν•˜λŠ” 상황이라 λžœλ€ν•œ κ°’μœΌλ‘œ μ΄ˆκΈ°ν™”ν–ˆμ§€λ§Œ, μ΄λ²ˆμ—λŠ” μ‹œν€€μŠ€ 번호λ₯Ό μƒˆλ‘­κ²Œ 생성할 ν•„μš”κ°€ μ—†μœΌλ―€λ‘œ κ·Έλƒ₯ μžμ‹ μ΄ μ΄λ²ˆμ— 보내야할 μˆœμ„œμ— λ§žλŠ” μ‹œν€€μŠ€ 번호λ₯Ό μ‚¬μš©ν•˜λ©΄ λ˜λŠ” 것이닀.

    • μš”μ²­μž ---SEQ: 1---> μˆ˜μ‹ μž
    • μš”μ²­μž <---ACK: 2--- μˆ˜μ‹ μž
    • μš”μ²­μž ---FIN: 2---> μˆ˜μ‹ μž

    즉, FIN ν”Œλž˜κ·Έλ§Œ 1둜 λ³€κ²½ν•΄μ„œ 보낸닀고 μƒκ°ν•˜λŠ” 게 νŽΈν•˜λ‹€. 이 ν”Œλž˜κ·Έμ˜ 의미λ₯Ό μ‰½κ²Œ μ–˜κΈ°ν•΄λ³΄μžλ©΄ β€œλ‚˜ 더 이상 ν•  말 μ—†μŒβ€ 정도이닀.

    μ΄λ•Œ μš”μ²­μžκ°€ λ¨Όμ € 적극적으둜 μ—°κ²° μ’…λ£Œ μš”μ²­μ„ λ³΄λ‚΄λŠ” 것이기 λ•Œλ¬Έμ— μš”μ²­μžλ₯Ό Active Closer, 이 μƒνƒœλ₯Ό λŠ₯동 폐쇄(Active Close)라고 ν•œλ‹€.

    localhost.initiator > localhost.receiver: Flags [F.], seq 701384376, ack 4101704148, win 6378

    ν•˜μ§€λ§Œ μš”μ²­μžκ°€ μˆ˜μ‹ μžμ—κ²Œ 보낸 μ—°κ²° μ’…λ£Œ μš”μ²­ νŒ¨ν‚·μ„ μΊ‘μ²˜ν•΄λ³΄λ‹ˆ F ν”Œλž˜κ·Έκ°€ μ•„λ‹ˆλΌ FIN+ACKλ₯Ό μ˜λ―Έν•˜λŠ” F. ν”Œλž˜κ·Έκ°€ μ„€μ •λ˜μ–΄μžˆλ‹€. tcpdumpλ₯Ό μ‚¬μš©ν•˜μ—¬ νŒ¨ν‚·μ„ μΊ‘μ²˜ν•œ λ‹€λ₯Έ λΈ”λ‘œκ·Έλ₯Ό 봐도 λŒ€λΆ€λΆ„ ν•„μžμ™€ 같은 상황을 κ²ͺκ³  μžˆμŒμ„ μ•Œ 수 μžˆμ—ˆλ‹€.

    λΆ„λͺ… μ΄λ‘ μ μœΌλ‘œλŠ” FIN νŒ¨ν‚·μ„ λ³΄λ‚΄μ•Όν•˜λŠ”λ° μ™œ 승인 번호λ₯Ό ν•¨κ»˜ λ¬Άμ–΄μ„œ FIN+ACK둜 보내고 μžˆλŠ” κ²ƒμΌκΉŒ?

    Half-Close 기법

    μš”μ²­μžκ°€ FIN+ACK νŒ¨ν‚·μ„ λ³΄λ‚΄λŠ” μ΄μœ λŠ” λ°”λ‘œ Half-CloseλΌλŠ” 기법을 μ‚¬μš©ν•˜κ³  있기 λ•Œλ¬Έμ΄λ‹€. Half-Close 기법은 말 κ·ΈλŒ€λ‘œ 연결을 μ’…λ£Œν•˜λ €κ³  ν•  λ•Œ μ™„μ „νžˆ μ’…λ£Œν•˜λŠ” 것이 μ•„λ‹ˆλΌ 반만 μ’…λ£Œν•˜λŠ” 것이닀.

    Half-Closeλ₯Ό μ‚¬μš©ν•˜λ©΄ μš”μ²­μžκ°€ 처음 λ³΄λ‚΄λŠ” FIN νŒ¨ν‚·μ— 승인 번호λ₯Ό ν•¨κ»˜ λ‹΄μ•„μ„œ λ³΄λ‚΄κ²Œ λ˜λŠ”λ°, μ΄λ•Œ 이 승인 번호의 μ˜λ―ΈλŠ” β€œμΌλ‹¨ 연결은 μ’…λ£Œν•  건데 κ·€λŠ” μ—΄μ–΄λ‘”λ‹€. 이 승인 λ²ˆν˜ΈκΉŒμ§€ μ²˜λ¦¬ν–ˆμœΌλ‹ˆκΉŒ λ§ˆμ € 보낼 κ±° 있으면 λ³΄λ‚΄β€λΌλŠ” μ˜λ―Έκ°€ λœλ‹€.

    즉, 반만 λ‹«κ² λ‹€λŠ” 말의 μ˜λ―ΈλŠ” 연결을 μ’…λ£Œν•  λ•Œ 전솑 슀트림과 μˆ˜μ‹  슀트림 쀑 ν•˜λ‚˜λ§Œ μš°μ„  λ‹«κ² λ‹€λŠ” 것을 μ˜λ―Έν•˜λŠ” 것이닀.

    이후 μˆ˜μ‹ μžλŠ” 미처 λͺ» 보낸 데이터가 μžˆλ‹€λ©΄ μ—΄μ‹¬νžˆ 보낼 것이고, 이에 μš”μ²­μžλŠ” 아직 μ‚΄μ•„μžˆλŠ” μˆ˜μ‹  μŠ€νŠΈλ¦Όμ„ μ‚¬μš©ν•˜μ—¬ 데이터λ₯Ό μ²˜λ¦¬ν•œ ν›„ ACK νŒ¨ν‚·μ„ μ‘λ‹΅μœΌλ‘œ 보낼 수 μžˆλ‹€. 이후 μˆ˜μ‹ μžκ°€ λͺ¨λ“  데이터λ₯Ό μ²˜λ¦¬ν•˜κ³ λ‚˜λ©΄ λ‹€μ‹œ μš”μ²­μžμ—κ²Œ FIN νŒ¨ν‚·μ„ λ³΄λƒ„μœΌλ‘œμ¨ λͺ¨λ“  데이터가 μ²˜λ¦¬λ˜μ—ˆλ‹€λŠ” μ‹ ν˜Έλ₯Ό 보내쀀닀.

    그럼 μš”μ²­μžλŠ” κ·Έλ•Œ λ‚˜λ¨Έμ§€ λ°˜μ„ λ‹«μœΌλ©΄μ„œ 쑰금 더 μ•ˆμ „ν•˜κ²Œ 연결을 μ’…λ£Œν•  수 μžˆλŠ” 것이닀.

    μ†ŒμΌ“ ν”„λ‘œκ·Έλž˜λ°μ„ ν•  λ•Œ μ—°κ²° μ’…λ£Œ ν•¨μˆ˜λ‘œ close()와 shutdown()을 μ‚¬μš©ν•  수 μžˆλŠ”λ°, μ΄λ•Œ shutdown() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ Half-Closeλ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€.

    shutdown(sockfd, SHUT_WR);

    λ§Œμ•½ μš”μ²­μžκ°€ close() ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ 호좜 μ¦‰μ‹œ OSμ—κ²Œ μ†ŒμΌ“μ˜ λ¦¬μ†ŒμŠ€λ₯Ό λ°˜ν™˜ν•˜λ©° λͺ¨λ“  슀트림이 νŒŒκΈ°λ˜λ―€λ‘œ FIN νŒ¨ν‚·μ„ 받은 μˆ˜μ‹ μžκ°€ 미처 λͺ» 보낸 데이터λ₯Ό λ’€λŠ¦κ²Œ μ „μ†‘ν•˜λ”λΌλ„ 더 이상 μ²˜λ¦¬ν•  수 μ—†λŠ” 상황이 λœλ‹€.

    μœ„μ˜ μ˜ˆμ œμ—μ„œλŠ” SHUT_WR 값을 두 번째 인자둜 μ‚¬μš©ν•¨μœΌλ‘œμ¨ 전솑 슀트림만 μš°μ„  λ‹«κ² λ‹€κ³  μ„ μ–Έν•œ 것이닀.

    이와 κ΄€λ ¨λœ 더 μžμ„Έν•œ μ •λ³΄λŠ” ꡬ글에 Half-Closeλ‚˜ μš°μ•„ν•œ μ’…λ£Œ λ“±μ˜ ν‚€μ›Œλ“œλ‘œ κ²€μƒ‰ν•˜λ©΄ λ§Žμ€ μžλ£Œκ°€ λ‚˜μ˜€λ‹ˆ ν•œλ²ˆ μ‚΄νŽ΄λ³΄λ„λ‘ ν•˜μž.

    CLOSE_WAIT

    4way closewait

    μš”μ²­μžμœΌλ‘œλΆ€ν„° FIN νŒ¨ν‚·μ„ 받은 μˆ˜μ‹ μžλŠ” μš”μ²­μžκ°€ 보낸 μ‹œν€€μŠ€ 번호 + 1둜 승인 번호λ₯Ό λ§Œλ“€μ–΄μ„œ λ‹€μ‹œ μš”μ²­μžμ—κ²Œ μ‘λ‹΅ν•΄μ£Όλ©΄μ„œ CLOSE_WAIT μƒνƒœλ‘œ λ“€μ–΄κ°„λ‹€.

    localhost.receiver > localhost.initiator: Flags [.], ack 701384377, win 6378

    μ•„κΉŒ μš”μ²­μžκ°€ FIN νŒ¨ν‚·μ˜ μ‹œν€€μŠ€ 번호둜 701384376을 λ³΄λƒˆμœΌλ‹ˆ μ΄λ²ˆμ— μˆ˜μ‹ μžκ°€ 응닡해쀄 승인 λ²ˆν˜ΈλŠ” 701384377이 λ˜λŠ” 것이닀.

    이후 μˆ˜μ‹ μžλŠ” μžμ‹ μ΄ 전솑할 데이터가 λ‚¨μ•„μžˆλ‹€λ©΄ μ΄μ–΄μ„œ 계속 μ „μ†‘ν•œ ν›„, λͺ¨λ“  전솑이 끝났닀면 λͺ…μ‹œμ μœΌλ‘œ close()λ‚˜ shutdown()κ³Ό 같은 ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜μ—¬ λ‹€μŒ λ‹¨κ³„λ‘œ λ„˜μ–΄κ°ˆ 것이닀.

    즉, μš”μ²­μžλŠ” μ–Έμ œ μˆ˜μ‹ μžμ˜ 데이터 μ²˜λ¦¬κ°€ 끝날지 λͺ¨λ₯΄λŠ” μƒνƒœμ΄κΈ° λ•Œλ¬Έμ— μˆ˜μ‹ μžκ°€ μž‘μ—…μ„ 마치고 λ‹€μ‹œ μ—°κ²° μ’…λ£Œ μŠΉμΈμ„ μ˜λ―Έν•˜λŠ” FIN νŒ¨ν‚·μ„ 보내쀄 λ•ŒκΉŒμ§€ λŒ€κΈ°ν•΄μ•Όν•œλ‹€λŠ” 말이 λœλ‹€.

    λ§Œμ•½ 이 λ‹¨κ³„μ—μ„œ μˆ˜μ‹ μžμ˜ 데이터 μ²˜λ¦¬κ°€ λλ‚˜λ„ μ—°κ²° μ’…λ£Œ ν•¨μˆ˜κ°€ λͺ…μ‹œμ μœΌλ‘œ ν˜ΈμΆœλ˜μ§€ μ•ŠμœΌλ©΄ λ‹€μŒ μƒνƒœλ‘œ λ„˜μ–΄κ°ˆ 수 μ—†κΈ° λ•Œλ¬Έμ— λ°λ“œλ½μ΄ λ°œμƒν•  κ°€λŠ₯성이 μžˆλ‹€.

    deadlock 구글의 자동 완성 검색어가 개발자들의 심정을 대변해주고 있다

    μ΄λ•Œ μˆ˜μ‹ μžλŠ” μƒλŒ€λ°©μœΌλ‘œλΆ€ν„° μ—°κ²° μ’…λ£Œ μš”μ²­μ„ 받은 후에야 μˆ˜λ™μ μœΌλ‘œ 연결을 μ’…λ£Œν•  μ€€λΉ„λ₯Ό ν•˜κΈ° λ•Œλ¬Έμ— μˆ˜μ‹ μžλ₯Ό Passive Closer, 이 μƒνƒœλ₯Ό μˆ˜λ™ 폐쇄(Passive Close)라고 ν•œλ‹€.

    FIN_WAIT_2

    4way finwait2

    μš”μ²­μžλŠ” μˆ˜μ‹ μžλ‘œλΆ€ν„° 승인 번호λ₯Ό λ°›κ³  μžμ‹ μ΄ λ³΄λƒˆλ˜ μ‹œν€€μŠ€ λ²ˆν˜Έμ™€ 승인 번호의 μ°¨κ°€ 1이 λ§žλŠ”μ§€ ν™•μΈν•œλ‹€. ν•˜μ§€λ§Œ 아직 μˆ˜μ‹ μžμ˜ 데이터 전솑이 μ „λΆ€ λλ‚˜μ§€ μ•Šμ•˜μ„ μˆ˜λ„ μžˆκΈ°μ— FIN_WAIT2 μƒνƒœλ‘œ λ“€μ–΄κ°€μ„œ μˆ˜μ‹ μžκ°€ μ—°κ²° μ’…λ£Œλ₯Ό ν—ˆλ½ν•˜λŠ” FIN νŒ¨ν‚·μ„ 보내쀄 λ•ŒκΉŒμ§€ κΈ°λ‹€λ¦°λ‹€.

    방금 CLOSE_WAIT μ„Ήμ…˜μ—μ„œ μ„€λͺ…ν–ˆλ“―이 μ—¬κΈ°μ„œλΆ€ν„°λŠ” μˆ˜μ‹ μžκ°€ λ‹€μ‹œ FIN νŒ¨ν‚·μ„ 보내쀄 λ•ŒκΉŒμ§€ μš”μ²­μžλŠ” 계속 λŒ€κΈ°ν•˜λŠ” μ‹œκ°„μ΄λ‹€.

    ν•˜μ§€λ§Œ CLOSE_WAIT와 λ‹€λ₯΄κ²Œ λ¬΄ν•œμ • λŒ€κΈ°λ§Œ ν•˜λŠ” 것은 μ•„λ‹ˆκ³  컀널 νŒŒλΌλ―Έν„°λ‘œ νƒ€μž„μ•„μ›ƒμ΄ μ •ν•΄μ ΈμžˆλŠ” 경우, 일정 μ‹œκ°„μ΄ κ²½κ³Όν•˜λ©΄ μžλ™μœΌλ‘œ λ‹€μŒ λ‹¨κ³„λ‘œ λ„˜μ–΄κ°ˆ 수 μžˆλ‹€.

    LAST_ACK

    4way lastack

    μˆ˜μ‹ μžλŠ” μžμ‹ μ΄ μ²˜λ¦¬ν•  데이터가 더 이상 μ—†λ‹€λ©΄ 연결을 μ’…λ£Œν•˜λŠ” ν•¨μˆ˜λ₯Ό λͺ…μ‹œμ μœΌλ‘œ ν˜ΈμΆœν•˜κ³ , μ•„κΉŒ μš”μ²­μžκ°€ λ³΄λƒˆλ˜ μ—°κ²° μ’…λ£Œ μš”μ²­μ— ν•©μ˜ν•œλ‹€λŠ” 의미둜 μš”μ²­μžμ—κ²Œ λ‹€μ‹œ FIN νŒ¨ν‚·μ„ 보낸닀.

    μ΄λ•Œ μˆ˜μ‹ μžκ°€ λ³΄λ‚΄λŠ” FIN νŒ¨ν‚·μ— λ‹΄κΈ°λŠ” μ‹œν€€μŠ€ λ„˜λ²„λŠ” μžμ‹ μ΄ μ΄λ²ˆμ— 전솑해야 ν•˜λŠ” λ°μ΄ν„°μ˜ μ‹œν€€μŠ€ 번호λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•˜λ©°, 승인 λ²ˆν˜ΈλŠ” λ§ˆμ§€λ§‰μœΌλ‘œ μžμ‹ μ΄ μ‘λ‹΅ν–ˆλ˜ 승인 번호λ₯Ό κ·ΈλŒ€λ‘œ μ‚¬μš©ν•œλ‹€.

    이후 μˆ˜μ‹ μžλŠ” LAST_ACK μƒνƒœλ‘œ λ“€μ–΄κ°€λ©° μš”μ²­μžκ°€ λ‹€μ‹œ 승인 번호λ₯Ό 보내쀄 λ•ŒκΉŒμ§€ λŒ€κΈ°ν•œλ‹€.

    TIME_WAIT

    4way timewait

    μˆ˜μ‹ μžκ°€ 보낸 FIN νŒ¨ν‚·μ„ 받은 μš”μ²­μžλŠ” λ‹€μ‹œ μˆ˜μ‹ μžκ°€ 보낸 μ‹œν€€μŠ€ 번호 + 1둜 승인 번호λ₯Ό μƒμ„±ν•˜μ—¬ μˆ˜μ‹ μžμ—κ²Œ ACK νŒ¨ν‚·μœΌλ‘œ μ‘λ‹΅ν•œλ‹€. 이후 μš”μ²­μžλŠ” TIME_WAIT μƒνƒœλ‘œ λ“€μ–΄κ°€λ©°, μ‹€μ§ˆμ μΈ μ—°κ²° μ’…λ£Œ 과정에 λ“€μ–΄κ°€κ²Œ λœλ‹€. μ΄λ•Œ TIME_WAIT의 역할은 μ˜λ„ν•˜μ§€ μ•Šμ€ μ—λŸ¬λ‘œ 인해 연결이 λ°λ“œλ½μ— λΉ μ§€λŠ” 것을 λ°©μ§€ν•˜λŠ” 것이닀.

    TIME_WAITμ—μ„œ λŒ€κΈ°ν•˜λŠ” μ‹œκ°„μ€ 2 MSL(Maximum Segement Lifetime)으둜 μ •μ˜λ˜μ–΄ 있으며, μ •ν™•ν•œ MSL의 μ‹œκ°„ 값은 컀널 νŒŒλΌλ―Έν„°λ‘œ μ •μ˜λ˜μ–΄μžˆλ‹€.

    $ sysctl net.inet.tcp | grep msl
    net.inet.tcp.msl: 15000

    ν•„μžμ˜ 컴퓨터인 OSX의 MSL은 15초둜 μ„€μ •λ˜μ–΄μžˆλ‹€. 즉, ν•„μžμ˜ μ»΄ν“¨ν„°λŠ” TIMEWAIT μƒνƒœμ—μ„œ 30초 정도 λŒ€κΈ°ν•œλ‹€λŠ” 것이닀. 참고둜 이 값은 λ³€κ²½ν•  수 μ—†κΈ° λ•Œλ¬Έμ— TIMEWAITμ—μ„œ μ†ŒλΉ„λ˜λŠ” μ‹œκ°„μ€ λ³€κ²½ν•  수 μ—†λ‹€.

    보톡 TCP νƒ€μž„μ•„μ›ƒ νŒŒλΌλ―Έν„°λ‘œ 많이 μ–ΈκΈ‰λ˜λŠ” net.ipv4.tcp_fin_timeout은 FINWAIT2의 νƒ€μž„μ•„μ›ƒμ„ μ‘°μ ˆν•  수 μžˆλŠ” 값이라 TIMEWAIT μƒνƒœμ—λŠ” ν•΄λ‹Ή 사항이 μ—†λ‹€.

    ν•˜μ§€λ§Œ CLOSEWAIT와 λ§ˆμ°¬κ°€μ§€λ‘œ μ—¬κΈ°μ„œλ„ λ°λ“œλ½μ΄ λ°œμƒν•  수 μžˆλ‹€. 그런 이유둜 λ§Žμ€ λ„€νŠΈμ›Œν¬ μ—”μ§€λ‹ˆμ–΄λ“€μ΄ μ—¬κΈ°μ„œ μ†ŒλΉ„λ˜λŠ” μ‹œκ°„μ„ μ€„μ΄κ±°λ‚˜ 운 λ‚˜μ˜κ²Œ λ°œμƒν•œ λ°λ“œλ½μ„ μ—†μ• κΈ° μœ„ν•΄ `tcptw_reuse` 컀널 νŒŒλΌλ―Έν„°λ₯Ό λ³€κ²½ν•˜λŠ” λ“± μ—¬λŸ¬κ°€μ§€ 방법을 μ‚¬μš©ν•˜κ³  μžˆλ‹€. (λ°λ“œλ½ ν”Όν•˜μžκ³  λ§Œλ“  μƒνƒœμΈλ° λ°λ“œλ½μ΄ λ°œμƒν•˜λŠ” ν˜„μ‹€)

    ν•˜μ§€λ§Œ μ—­μ‹œ κ·Έλƒ₯ κ°€λ§Œ λƒ…λ‘λŠ” 게 제일 μ’‹λ‹€κ³ λ“€ ν•œλ‹€.

    CLOSED(μˆ˜μ‹ μž)

    4way closed server

    μš”μ²­μžκ°€ 보낸 ACK νŒ¨ν‚·μ„ 받은 μˆ˜μ‹ μžλŠ” CLOSED μƒνƒœλ‘œ λ“€μ–΄κ°€λ©° 연결을 μ™„μ „νžˆ μ’…λ£Œν•œλ‹€.

    CLOSED(μš”μ²­μž)

    4way closed client

    TIME_WAIT μƒνƒœμ—μ„œ 2 MSL만큼 μ‹œκ°„μ΄ μ§€λ‚˜λ©΄ μš”μ²­μžλ„ CLOSED μƒνƒœλ‘œ λ³€κ²½λœλ‹€. μœ„μ—μ„œ μ„€λͺ…ν–ˆλ“―이 이 μ‹œκ°„μ€ 컀널 νŒŒλΌλ―Έν„°μ— κ³ μ •λ˜μ–΄ 있고, ν•„μžκ°€ μ‚¬μš©ν•˜κ³  μžˆλŠ” OSX의 경우 30초 정도이닀.

    마치며

    μ΄λ ‡κ²Œ 두 번째 TCP 주제인 ν•Έλ“œμ‰μ΄ν¬μ— λŒ€ν•œ ν¬μŠ€νŒ…μ„ λ§ˆμ³€λ‹€. TCP에 λŒ€ν•΄μ„œ ν•™κ΅μ—μ„œ 배우긴 ν–ˆμ§€λ§Œ μ΄λ ‡κ²Œ 각 μƒνƒœμ— λŒ€ν•΄μ„œ μžμ„Ένžˆ κ³΅λΆ€ν•˜μ§„ μ•Šμ•˜κΈ° λ•Œλ¬Έμ— λ‚˜λ¦„ μƒˆλ‘œμš΄ κ²½ν—˜μ΄μ—ˆλ‹€.

    이 ν¬μŠ€νŒ…μ„ μž‘μ„±ν•˜λ©΄μ„œ TCPκ°€ λ‹¨μˆœνžˆ 연결을 μƒμ„±ν•˜κ³  μ’…λ£Œν•˜λŠ”λ°λ§Œ 해도 신뒰성을 ν™•λ³΄ν•˜κΈ° μœ„ν•΄ μ–Όλ§ˆλ‚˜ λ§Žμ€ μž‘μ—…μ„ ν•˜λŠ”μ§€ μ•Œ 수 μžˆμ—ˆλ‹€. (λ”λΆˆμ–΄ ꡬ글이 μ™œ HTTP/3에 UDPλ₯Ό μ‚¬μš©ν–ˆλŠ”μ§€ μ•Œ 것 κ°™μ•˜λ‹€β€¦)

    μ²˜μŒμ—λŠ” ν•„μž λΈ”λ‘œκ·Έ 둜컬 μ„œλ²„μ™€ λΈŒλΌμš°μ €μ˜ ν•Έλ“œμ‰μ΄ν¬λ₯Ό μΊ‘μ²˜ν•΄λ³΄λ €κ³  ν–ˆλŠ”λ°, 이 μΉœκ΅¬λ“€μ€ λ‹¨μˆœν•œ λͺ‡ 개의 메세지λ₯Ό μ£Όκ³  λ°›λŠ” μˆ˜μ€€μ΄ μ•„λ‹ˆλΌ λŒ€λŸ‰μ˜ 데이터λ₯Ό μ£Όκ³  λ°›λŠ” μ‚¬μ΄λ‹€λ³΄λ‹ˆ ν•„μžκ°€ μ›ν•˜λŠ” 뢀뢄을 μΆ”μ ν•˜κΈ°κ°€ 쉽지 μ•Šμ•˜λ‹€.

    κ·Έλž˜μ„œ μ˜€λžœλ§Œμ— κ°„λ‹¨ν•œ μ†ŒμΌ“ ν”„λ‘œκ·Έλž˜λ°μ„ ν•˜κ²Œ λ˜μ—ˆλŠ”λ°, μŒβ€¦ ν•˜λ„ μ˜€λžœλ§Œμ— Cλ₯Ό μ‚¬μš©ν•˜λ‹€λ³΄λ‹ˆ 손에 μ•ˆ μ΅μ–΄μ„œ κ½€λ‚˜ κ³ μƒν•˜κΈ΄ ν–ˆμ§€λ§Œ λ‚˜λ¦„ μž¬λ―Έμžˆμ—ˆλ‹€. CλŠ” μ—­μ‹œ 가끔 ν•΄μ•Ό μž¬λ°ŒλŠ” 것 κ°™λ‹€.

    ν˜Ήμ‹œ ν•„μžκ°€ 예제둜 μ‚¬μš©ν•œ μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ„ 직접 싀행해보고 μ‹ΆμœΌμ‹  뢄은 ν•„μžμ˜ κΉƒν—ˆλΈŒ λ ˆνŒŒμ§€ν† λ¦¬μ—μ„œ 클둠 받을 수 μžˆλ‹€. κ°„λ‹¨ν•œ λ©”μ„Έμ§€λ§Œ μ„œλ‘œ μ£Όκ³  λ°›λŠ” μ–΄ν”Œλ¦¬μΌ€μ΄μ…˜μ΄λ‹ˆ tcpdumpλ₯Ό μ‚¬μš©ν•΄μ„œ νŒ¨ν‚·μ„ 듀여닀보기도 ν•œκ²° νŽΈν•  것이닀.

    μ΄μƒμœΌλ‘œ TCPκ°€ 연결을 μƒμ„±ν•˜κ³  μ’…λ£Œν•˜λŠ” 방법, ν•Έλ“œμ‰μ΄ν¬ ν¬μŠ€νŒ…μ„ λ§ˆμΉœλ‹€.

    Evan Moon

    🐒 거뢁이처럼 μ‚΄μž

    κ°œλ°œμ„ μž˜ν•˜κΈ° μœ„ν•΄μ„œκ°€ μ•„λ‹Œ κ°œλ°œμ„ 즐기기 μœ„ν•΄ λ…Έλ ₯ν•˜λŠ” κ°œλ°œμžμž…λ‹ˆλ‹€. μ‚¬μ†Œν•œ 생각 정리뢀터 νŠœν† λ¦¬μ–Ό, μ‚½μ§ˆκΈ° 정도λ₯Ό 주둜 끄적이고 μžˆμŠ΅λ‹ˆλ‹€.