WebSocket

Phase 1: TCP Connection Establishment (TCP 3-Way Handshake)

이 과정은 데이터λ₯Ό μ£Όκ³ λ°›κΈ° μ „, 논리적인 연결을 λ§Œλ“œλŠ” κ³Όμ •μž…λ‹ˆλ‹€.

즉, μ‹ λ’°μ„± μžˆλŠ” 전솑 계측 μ„Έμ…˜μ„ μƒμ„±ν•˜κ³ , μ–‘λ‹¨μ˜ μ‹œν€€μŠ€ 번호(ISN)λ₯Ό λ™κΈ°ν™”ν•˜μ—¬ ESTABLISHED μƒνƒœλ‘œ μ „μ΄ν•©λ‹ˆλ‹€.

[Packet-171]: Client β†’ Server (SYN)

1. ν΄λΌμ΄μ–ΈνŠΈκ°€ Active Open을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.

ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ²„μ— 연결을 λŠ₯λ™μ μœΌλ‘œ μš”μ²­ν•˜λŠ” κ³Όμ •μœΌλ‘œ, connect() μ‹œμŠ€ν…œ μ½œμ„ ν˜ΈμΆœν•˜μ—¬ SYN νŒ¨ν‚·μ„ μ „μ†‘ν•©λ‹ˆλ‹€.

2. TCP ν—€λ”μ˜ SYN ν”Œλž˜κ·Έλ₯Ό 1둜 μ„€μ •ν•˜κ³ , μžμ‹ μ˜ 초기 μ‹œν€€μŠ€ 번호(ISN)λ₯Ό μƒμ„±ν•˜μ—¬ λ³΄λƒ…λ‹ˆλ‹€.

μ΄λ―Έμ§€μ˜ 171번 νŒ¨ν‚·μ˜ Infoλ₯Ό 보면 Seq=0으둜 μ„€μ •λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.

이것은 와이어샀크가 보기 νŽΈν•˜λΌκ³  β€˜κ°€μ§œλ‘œ λ³΄μ—¬μ£ΌλŠ” 숫자(Relative Sequence Number)β€™μž…λ‹ˆλ‹€.

μ‹€μ œλ‘œλŠ” 0이 μ•„λ‹ˆλΌ 40μ–΅ 개의 숫자 쀑 λ¬΄μž‘μœ„λ‘œ μƒμ„±λœ κ±°λŒ€ν•œ μˆ«μžμž…λ‹ˆλ‹€.

νŒ¨ν‚· νŒ¨λ„μ˜ Transmission Control Protocolλ₯Ό ν™•μž₯ν•˜λ©΄ 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

이 μ•ˆμ— Sequence Number: 0 (relative sequence number)라고 적힌 쀄이 보이고,

κ·Έ λ°”λ‘œ 밑에 Sequence Number (raw): 2669254254 라고 적힌 raw 값이 λ°”λ‘œ ν΄λΌμ΄μ–ΈνŠΈ OSκ°€ μƒμ„±ν•œ μ§„μ§œ ISNμž…λ‹ˆλ‹€.

πŸ€” 그럼 μ™œ 0으둜 λ³΄μ—¬μ£Όλ‚˜μš”?

  • 2669254254 λ‹€μŒμ— 2669254255κ°€ μ™”λŠ”μ§€ ν™•μΈν•˜λŠ” 것보닀, 0 λ‹€μŒμ— 1이 μ™”λŠ”μ§€ ν™•μΈν•˜λŠ” 게 뢄석가 μž…μž₯μ—μ„œ νŽΈν•˜κΈ° λ•Œλ¬Έμ— 와이어샀크가 μžλ™μœΌλ‘œ κ³„μ‚°ν•΄μ„œ λ³΄μ—¬μ€λ‹ˆλ‹€.

3. μƒνƒœ 전이: ν΄λΌμ΄μ–ΈνŠΈλŠ” CLOSED β†’ SYN_SENT μƒνƒœλ‘œ μ „μ΄ν•©λ‹ˆλ‹€.

μƒνƒœ 전이 뢀뢄은 와이어샀크 ν™”λ©΄μ—μ„œ μ°Ύμ•„λ³Ό 수 μ—†μ—ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ μ™œ μ „μ΄λ˜λŠ”μ§€ μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

  • νŒ¨ν‚·(Packet)은 λ„€νŠΈμ›Œν¬ 선을 타고 λ‚ μ•„κ°€λŠ” μ •λ³΄μž…λ‹ˆλ‹€.

  • μƒνƒœ(State)λŠ” 정보 μ•ˆμ— μžˆλŠ” μ„ΈλΆ€ μ •λ³΄μž…λ‹ˆλ‹€. νŒ¨ν‚· ν—€λ”μ—λŠ” νŒ¨ν‚·μ„ μ „μ†‘ν•˜λŠ” μˆœκ°„, λŒ€μƒμ˜ λ‹΅μž₯을 κΈ°λ‹€λ¦¬λŠ” λͺ¨λ“œ(SYN_SENT)둜 λ³€ν•©λ‹ˆλ‹€.

πŸ€” SYN_SENT μƒνƒœλŠ” μ–΄λ–»κ²Œ 확인할 수 μžˆλ‚˜μš”?

μ™€μ΄μ–΄μƒ€ν¬μ—μ„œλŠ” 직접 확인할 수 μ—†κΈ° λ•Œλ¬Έμ— νŒ¨ν‚· λ‚΄λΆ€μ˜ ν”Œλž˜κ·Έλ₯Ό 톡해 μ—­μΆ”λ‘ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • Flags의 ν•­λͺ©μ„ ν™•μž₯ν•˜λ©΄, Syn: Set(1) 인 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

TCP/IP State Transition Diagram (RFC 793) SYN-SENT: represents waiting for a matching connection request after having sent a connection request.

TCP κ·œμ•½(RFC 793)에 λ”°λ₯΄λ©΄, SYN을 보낸 직후 OSλŠ” 무쑰건 SYN_SENT μƒνƒœλ‘œ 바뀐닀고 λͺ…μ‹œλ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€. κ·Έλž˜μ„œ ν΄λΌμ΄μ–ΈνŠΈλŠ” SYN_SENT μƒνƒœλΌκ³  결둠을 내릴 수 μžˆμŠ΅λ‹ˆλ‹€.

[Packet-172]: Server β†’ Client (SYN, ACK)

1. μ„œλ²„κ°€ Passive Open μƒνƒœμ—μ„œ μš”μ²­μ„ μˆ˜λ½ν•©λ‹ˆλ‹€.

μ„œλ²„λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹€ν–‰λ˜λ©΄μ„œ 이미 bind()와 listen() μ‹œμŠ€ν…œ μ½œμ„ ν˜ΈμΆœν•˜μ—¬ μˆ˜λ™μ  개방(Passive Open) μƒνƒœλ‘œ μ§„μž…ν•˜μ—¬ LISTEN μƒνƒœμž…λ‹ˆλ‹€.

μ„œλ²„λŠ” ν΄λΌμ΄μ–ΈνŠΈμ˜ μ—°κ²° μš”μ²­(SYN)을 κΈ°λ‹€λ¦¬λ©΄μ„œ, SYN을 μˆ˜μ‹ ν•˜λ©΄ 이에 λŒ€ν•œ 응닡 ν”„λ‘œμ„ΈμŠ€λ₯Ό μ‹œμž‘ν•©λ‹ˆλ‹€.

2. TCP 헀더 μ„€μ •

  • SYN: μ„œλ²„λ„ μžμ‹ μ˜ ISN을 μƒμ„±ν•˜μ—¬ 동기화 μš”μ²­μ„ λ³΄λƒ…λ‹ˆλ‹€.

  • ACK: ν΄λΌμ΄μ–ΈνŠΈμ˜ ISN에 1을 λ”ν•œ κ°’(ACK=1)을 승인 번호둜 λ³΄λƒ…λ‹ˆλ‹€.

    • Acknowledgment number (raw): 2669254255 둜 λ‚˜νƒ€λ‚˜μžˆμŠ΅λ‹ˆλ‹€.

πŸ€” κ·Έλ ‡λ‹€λ©΄ μ™œ 1을 λ”ν• κΉŒμš”?

TCP Segment의 Len=0인 것을 보면, 이 νŒ¨ν‚·μ—λŠ” 데이터(Payload)κ°€ μ—†λ‹€λŠ” 것을 μ•Œ 수 μžˆμŠ΅λ‹ˆλ‹€.

일반적으둜 데이터가 μ—†μœΌλ©΄ ACK λ²ˆν˜ΈλŠ” μ¦κ°€ν•˜μ§€ μ•Šμ•„μ•Ό ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ TCP κ·œμ•½(RFC 793)μ—λŠ” νŠΉμˆ˜ν•œ κ·œμΉ™μ΄ μžˆμŠ΅λ‹ˆλ‹€.

β€œThe segment length (SEG.LEN) includes both data and sequence space occupying controls. When a SYN is present then SEG.SEQ is the sequence number of the SYN.”

μ΄λŠ”, λ‹€μŒκ³Ό 같이 해석할 수 μžˆμŠ΅λ‹ˆλ‹€.

"SYN ν”Œλž˜κ·Έμ™€ FIN ν”Œλž˜κ·ΈλŠ” 데이터가 없더라도 λ…Όλ¦¬μ μœΌλ‘œ 1λ°”μ΄νŠΈμ˜ μ‹œν€€μŠ€ 번호λ₯Ό μ†ŒλΉ„(Consume)ν•œλ‹€.”

즉, μ„œλ²„ μž…μž₯μ—μ„œ 172번 νŒ¨ν‚·(SYN + ACK)을 보낼 λ•Œ λ…Όλ¦¬λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • ν΄λΌμ΄μ–ΈνŠΈκ°€ 보낸 171번 νŒ¨ν‚·μ„ λ°›μŠ΅λ‹ˆλ‹€.

  • 데이터(Payload)λŠ” μ—†μ§€λ§Œ, SYN ν”Œλž˜κ·Έκ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€.

  • SYN ν”Œλž˜κ·Έλ₯Ό 데이터 1byte 처럼 μ·¨κΈ‰ν•΄μ„œ μ²˜λ¦¬ν•©λ‹ˆλ‹€.

  • κ·Έλž˜μ„œ μ„œλ²„λŠ” 받은 번호(2669254254) + 1인 2669254255λ₯Ό λ‹€μŒ 번호둜 κΈ°λŒ€ν•˜κ³  응닡(ACK)ν•©λ‹ˆλ‹€.

μ΄λŸ¬ν•œ μ„€κ³„μ˜ μž₯점은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • μΌκ΄€λœ 슀트림 λͺ¨λΈ

    • μ—°κ²° μ„€μ •/μ’…λ£Œκ°€ λͺ¨λ‘ ν•˜λ‚˜μ˜ μ—°μ†λœ μ‹œν€€μŠ€ 번호 곡간 μœ„μ— λ†“μž…λ‹ˆλ‹€.

    • μ†‘μˆ˜μ‹  μ–‘μͺ½μ΄ β€˜μ–΄λ””κΉŒμ§€ μ²˜λ¦¬ν–ˆλŠ”μ§€β€™λ₯Ό ν•˜λ‚˜μ˜ 숫자(ACK)둜만 ν‘œν˜„ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

  • μž¬μ „μ†‘/쀑볡 처리 λ‹¨μˆœν™”

    • SYN/FIN도 μ‹œν€€μŠ€ 번호λ₯Ό κ°–κΈ° λ•Œλ¬Έμ—, β€˜μ΄ μ‹œν€€μŠ€ ꡬ간은 이미 받은 건가?β€™λ§Œ ν™•μΈν•˜λ©΄ 쀑볡/μ§€μ—°/μž¬μ—°μ†‘ μ—¬λΆ€λ₯Ό νŒλ‹¨ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    • μ œμ–΄ ν”Œλž˜κ·ΈλΌκ³  ν•΄μ„œ 별도 μ˜ˆμ™Έ 처리 λ‘œμ§μ„ 두지 μ•Šμ•„λ„ λ©λ‹ˆλ‹€.

3. μƒνƒœ 전이: μ„œλ²„λŠ” LISTEN β†’ SYN_RCVD μƒνƒœλ‘œ μ „μ΄ν•©λ‹ˆλ‹€.

ν΄λΌμ΄μ–ΈνŠΈμ˜ SYN νŒ¨ν‚·μ„ λ°›μœΌλ©΄, μ„œλ²„λŠ” 이에 λŒ€ν•œ μ‘λ‹΅μœΌλ‘œ SYN-ACKλ₯Ό 보내 μ—°κ²° μš”μ²­μ„ 확인(ACK)ν•˜κ³  μ—°κ²° 수립 과정에 μ§„μž…ν•©λ‹ˆλ‹€.

SYN-ACKλ₯Ό λ³΄λƒˆμœΌλ―€λ‘œ, 이제 ν΄λΌμ΄μ–ΈνŠΈμ˜ λ§ˆμ§€λ§‰ 응닡을 기닀리기 μœ„ν•΄ μ„œλ²„μ˜ OS μ†ŒμΌ“ μƒνƒœλ₯Ό SYN_RCVD둜 λ³€κ²½ν•©λ‹ˆλ‹€.

[Packet-173]: Client β†’ Server(SYN, ACK)

1. ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„œλ²„μ˜ 동기화 μš”μ²­μ„ ν™•μΈν•©λ‹ˆλ‹€.

  • μ„œλ²„μ˜ ISN에 1을 λ”ν•œ κ°’(ACK=1)을 λ³΄λƒ…λ‹ˆλ‹€.

2. μƒνƒœ 전이

  • ν΄λΌμ΄μ–ΈνŠΈλŠ” 이 νŒ¨ν‚·μ„ μ „μ†‘ν•˜λ©° SYN_SENT β†’ ESTABLISHED μƒνƒœκ°€ λ©λ‹ˆλ‹€.

  • μ„œλ²„λŠ” 이 νŒ¨ν‚·μ„ μˆ˜μ‹ ν•˜λ©° SYN_RECEIVED β†’ ESTABLISHED μƒνƒœκ°€ λ©λ‹ˆλ‹€.

  • μ΄λŠ” ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„ κ°„ 논리적인 데이터 전솑 κ²½λ‘œκ°€ 생성됨을 μ˜λ―Έν•©λ‹ˆλ‹€.

Phase 2. Protocol Upgrade Handshake (HTTP β†’ WebSocket)

이 과정은 Application Layer(L7) ν”„λ‘œν† μ½œμ„ HTTP/1.1μ—μ„œ WebSocket으둜 μ „ν™˜ν•©λ‹ˆλ‹€.

[Packet-174]: Client β†’ Server (HTTP GET /ws)

ν΄λΌμ΄μ–ΈνŠΈκ°€ WebSocket Handshakeλ₯Ό μœ„ν•œ Requestλ₯Ό μ „μ†‘ν•©λ‹ˆλ‹€.

Hypertext Transfer Protocol μ„Ήμ…˜μ€ TCP νŽ˜μ΄λ‘œλ“œλ₯Ό ν•΄μ„ν•œ κ²°κ³Όμž…λ‹ˆλ‹€.

  • Upgrade: websocket β†’ ν”„λ‘œν† μ½œ λ³€κ²½ μš”μ²­

  • Connection: Upgrade β†’ 홉(Hop)κ°„ μ—…κ·Έλ ˆμ΄λ“œ μ˜΅μ…˜ λͺ…μ‹œ (ν•„μˆ˜ 헀더)

  • Sec-Websocket-Key: tgK1hM8wU7SHuWxUJds40Q== β†’ λ¬΄μž‘μœ„ 16bytes 값을 Base64 μΈμ½”λ”©ν•œ μ±Œλ¦°μ§€ ν‚€

[Packet-175]: Server β†’ Client (ACK)

μ„œλ²„ TCP κ³„μΈ΅μ˜ μˆ˜μ‹  ν™•μΈμž…λ‹ˆλ‹€.

L7 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ νŒ¨ν‚· 174번 μš”μ²­μ„ μ²˜λ¦¬ν•˜μ—¬ 응닡(101 Switching Protocols)을 μƒμ„±ν•˜λŠ” λ™μ•ˆ, L4(OS 컀널)λŠ” μˆ˜μ‹  버퍼에 데이터가 μ μž¬λ˜λŠ” μ¦‰μ‹œ λ…λ¦½μ μœΌλ‘œ TCP ACK(Packet-175)λ₯Ό 솑신 츑에 λ³΄λƒ…λ‹ˆλ‹€.

  • μ΄λŠ” TCP의 μ‹ λ’°μ„± 보μž₯ λ©”μ»€λ‹ˆμ¦˜μ΄λ©°, β€˜λ°μ΄ν„°κ°€ μœ μ‹€ 없이 λ„μ°©ν–ˆμŒβ€™μ„ 솑신 츑에 μ•Œλ¦¬λŠ” μ ˆμ°¨μž…λ‹ˆλ‹€.

[Packet-193]: Server β†’ Client (HTTP 101 Switching Protocols)

μ„œλ²„κ°€ Handshake Responseλ₯Ό μ „μ†‘ν•˜λ©° ν”„λ‘œν† μ½œ μ „ν™˜μ„ μŠΉμΈν•©λ‹ˆλ‹€.

  • HTTP/1.1 Status Code: 101: ν”„λ‘œν† μ½œ μ „ν™˜ 승인 응닡 μƒνƒœ μ½”λ“œ

  • Sec-WebSocket-Accept: fVka1UgF5mcoCU07ZlpLj/mPUR0=: ν΄λΌμ΄μ–ΈνŠΈκ°€ 보낸 Key와 Magic GUIDλ₯Ό κ²°ν•© ν›„ SHA-1 ν•΄μ‹±ν•˜κ³ , 이λ₯Ό λ‹€μ‹œ Base64 μΈμ½”λ”©ν•˜μ—¬ μƒμ„±ν•œ 응닡 ν‚€μž…λ‹ˆλ‹€.

  • 이 과정을 톡해 μƒν˜Έ 연결을 κ²€μ¦ν•©λ‹ˆλ‹€.

[Packet-194]: Client β†’ Server (ACK)

ν΄λΌμ΄μ–ΈνŠΈ μΈ‘ OSκ°€ μ„œλ²„μ˜ 193번 νŒ¨ν‚·(Handshake Response) μˆ˜μ‹ μ„ ν™•μΈν•©λ‹ˆλ‹€.

이 μ‹œμ  이후 ν•΄λ‹Ή TCP μ„Έμ…˜μ˜ PayloadλŠ” 더 이상 HTTP κ·œμΉ™μ΄ μ•„λ‹Œ WebSocket Frame κ·œκ²©μ„ λ”°λ₯΄λ©°, μ–‘λ°©ν–₯ 톡신(Full-Duplex)이 μ‹œμž‘λ©λ‹ˆλ‹€.

Phase 3. Data Transmission (WebSocket Frames)

ν΄λΌμ΄μ–ΈνŠΈμ™€ μ„œλ²„λŠ” HTTP 101 Switching Protocols 응닡 이후,

TCP μ—°κ²° μœ„μ—μ„œ WebSocket ν”„λ‘œν† μ½œμ„ μ‚¬μš©ν•˜μ—¬ ν”„λ ˆμž„ λ‹¨μœ„μ˜ Full-Duplex 톡신을 μˆ˜ν–‰ν•©λ‹ˆλ‹€.

이 λ‹¨κ³„μ—μ„œλŠ” HTTP λ©”μ‹œμ§€κ°€ μ•„λ‹Œ, RFC 6455에 μ •μ˜λœ WebSocket Frame ν˜•μ‹μ΄ TCP Payload에 λ‹΄κΉλ‹ˆλ‹€.

[Packet-199]: Server β†’ Client (WebSocket Text [FIN])

  1. μ„œλ²„κ°€ ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ ν…μŠ€νŠΈ λ©”μ‹œμ§€(데이터)λ₯Ό PUSH ν•©λ‹ˆλ‹€.

Wireshark에 WebSocket νŠΈλ¦¬κ°€ ν‘œμ‹œλ˜λŠ” 것은, 이 νŒ¨ν‚·μ΄ TCP Payloadλ₯Ό HTTPκ°€ μ•„λ‹ˆλΌ WebSocket ν”„λ‘œν† μ½œλ‘œ ν•΄μ„ν–ˆλ‹€λŠ” μ˜λ―Έμž…λ‹ˆλ‹€.

ν”„λ ˆμž„ κ΅¬μ‘°λŠ” λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • FIN: True

  • Opcode: Text (1) β†’ 1은 ν…μŠ€νŠΈ ν”„λ ˆμž„ μ’…λ₯˜μ΄λ©° Payloadκ°€ UTF-8 Textλ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.

  • Mask: False β†’ μ„œλ²„ to ν΄λΌμ΄μ–ΈνŠΈλŠ” 보톡 Falseμž…λ‹ˆλ‹€.

  • Payload length: 81 β†’ μ‹€μ œ 데이터 길이λ₯Ό μ˜λ―Έν•©λ‹ˆλ‹€.

  1. Payload λ‚΄μš©

Line-based text dataλŠ” 이미 WebSocket ν”„λ ˆμž„ μ•ˆμ— μžˆλŠ” νŽ˜μ΄λ‘œλ“œλ₯Ό, Wiresharkκ°€ μ‚¬λžŒμ΄ 읽기 μ’‹κ²Œ ν’€μ–΄μ„œ λ³΄μ—¬μ£ΌλŠ” μ˜μ—­μž…λ‹ˆλ‹€. 이미지에 λ³΄μ—¬μ§€λŠ” JSON λ©”μ‹œμ§€λŠ” Payloadλ₯Ό UTF-8 ν…μŠ€νŠΈλ‘œ λ””μ½”λ”©ν•œ κ²°κ³Όμž…λ‹ˆλ‹€.

  1. WebSocket Opcode μ’…λ₯˜ (RFC 6455)

λ©”μ‹œμ§€ 데이터 ν”„λ ˆμž„ (Data Frames): ν…μŠ€νŠΈ/λ°”μ΄λ„ˆλ¦¬ λ©”μ‹œμ§€λ₯Ό μ „μ†‘ν•˜λŠ” ν”„λ ˆμž„

Opcode
이름
의미

0x0

Continuation Frame

이전 ν”„λ ˆμž„μ˜ 연속 데이터

0x1

Text Frame

UTF-8 ν…μŠ€νŠΈ 데이터

0x2

Binary Frame

λ°”μ΄λ„ˆλ¦¬ 데이터

μ œμ–΄ ν”„λ ˆμž„ (Control Frames): μ—°κ²° κ΄€λ¦¬Β·μƒνƒœ μ œμ–΄λ₯Ό μœ„ν•œ ν”„λ ˆμž„

Opcode
이름
의미

0x8

Connection Close

μ—°κ²° μ’…λ£Œ μš”μ²­

0x9

Ping

μƒνƒœ 확인(Ping) μš”μ²­

0xA

Pong

Ping에 λŒ€ν•œ 응닡

[Packet-199]: Server β†’ Client (WebSocket Text [FIN])

TCP κ³„μΈ΅μ˜ μˆ˜μ‹  확인 κ³Όμ •μž…λ‹ˆλ‹€.

WebSocket은 TCP μœ„μ—μ„œ λ™μž‘ν•˜λ―€λ‘œ, μ„œλ²„κ°€ 보낸 [Packet-199]의 TCP μ„Έκ·Έλ¨ΌνŠΈμ— λŒ€ν•΄ ν΄λΌμ΄μ–ΈνŠΈλŠ” TCP ACK νŒ¨ν‚·μ„ 보내 μˆ˜μ‹ μ„ ν™•μΈν•©λ‹ˆλ‹€.

TCP Streamκ³Ό WebSocket Frame 관계

WebSocket 톡신은 μ—°κ²° 수λͺ… λ™μ•ˆ ν•˜λ‚˜μ˜ TCP μ—°κ²°(TCP Stream) μœ„μ—μ„œ μˆ˜ν–‰λ©λ‹ˆλ‹€.

TCP κ³„μΈ΅μ—μ„œ WebSocket λ°μ΄ν„°λŠ” μ—°μ†λœ λ°”μ΄νŠΈ 슀트림의 일뢀(Payload) 둜 μ „λ‹¬λ˜λ©°, TCPλŠ” WebSocket ν”„λ ˆμž„μ˜ 경계λ₯Ό μΈμ§€ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

λ”°λΌμ„œ, WebSocket ν”„λ ˆμž„μ˜ λ©”μ‹œμ§€ κ²½κ³„λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜ 계측(WebSocket ν”„λ‘œν† μ½œ) μ—μ„œλ§Œ 의미λ₯Ό κ°€μ§€λ©°, μ‹ λ’°μ„±, μˆœμ„œ 보μž₯, μž¬μ „μ†‘μ€ TCP κ³„μΈ΅μ—μ„œ λ‹΄λ‹Ήν•©λ‹ˆλ‹€.

Phase 4. WebSocket Closing Handshake (Graceful Shutdown)

WebSocket은 Application Layerμ—μ„œ 양츑이 μ’…λ£Œ μ˜μ‚¬λ₯Ό λͺ…μ‹œμ μœΌλ‘œ κ΅ν™˜ν•˜μ—¬, 비정상 μ’…λ£Œμ™€ 정상 μ’…λ£Œλ₯Ό κ΅¬λΆ„ν•©λ‹ˆλ‹€.

  • 정상 μ’…λ£Œ: Close Frame을 μ£Όκ³ λ°›λŠ” Closing Handshake 절차λ₯Ό μ™„λ£Œν•œ ν›„ TCP 연결을 λŠλŠ” 것.

  • 비정상 μ’…λ£Œ: 이 절차 없이 κ°‘μžκΈ° TCP 연결이 λŠκΈ°λŠ” 경우.

[Packet-322]: Server β†’ Client (WebSocket Connection Close [FIN])

  1. μ„œλ²„κ°€ λ¨Όμ € Close Frame을 μ „μ†‘ν•˜λ©° Websocket μ—°κ²° ν•΄μ œ 절차λ₯Ό κ°œμ‹œν•©λ‹ˆλ‹€.

WebSocket 연결을 λŠμ„ λ•Œλ„ μ’…λ£Œ μš”μ²­Β·μ‘λ‹΅μ€ λͺ¨λ‘ HTTPκ°€ μ•„λ‹Œ WebSocket ν”„λ ˆμž„μœΌλ‘œ μ£Όκ³ λ°›κ³ , 이 ν”„λ ˆμž„μ΄ μ‹€λ¦° TCP μ„Έκ·Έλ¨ΌνŠΈλŠ” ν”νžˆ PSH, ACK ν”Œλž˜κ·Έλ₯Ό κ°€μ§„ 일반 데이터 μ„Έκ·Έλ¨ΌνŠΈμ²˜λŸΌ μ „μ†‘λ©λ‹ˆλ‹€.

λˆ„κ°€ λ¨Όμ € Close Frame을 λ³΄λ‚΄λŠ”μ§€ μ •ν•΄μ§„ κ·œμΉ™μ€ μ—†κ³ , ν˜„μž¬ κΈ€μ—μ„œλŠ” μ„œλ²„κ°€ λ¨Όμ € Close ν”„λ ˆμž„μ„ μ „μ†‘ν•©λ‹ˆλ‹€.

  • μ’…λ£Œ μš”μ²­μ˜ μ£Όμ²΄λŠ” ν΄λΌμ΄μ–ΈνŠΈκ°€ 될 μˆ˜λ„ μžˆμœΌλ‚˜, ν˜„μž¬ νŒ¨ν‚· νλ¦„μ—μ„œλŠ” μ„œλ²„κ°€ μ£Όμ²΄μž…λ‹ˆλ‹€.

  • FIN bit=1: ν”„λ ˆμž„ μ’…λ£Œλ₯Ό μ˜λ―Έν•˜λ©°, TCP FINκ³ΌλŠ” λ‹€λ₯Έ κ°œλ…

ν”„λ ˆμž„ ꡬ쑰:

  • Opcode=0x8: μ—°κ²° μ’…λ£Œ μš”μ²­

  • Payload: μƒνƒœ μ½”λ“œ(Status Code, 예: 1000 Normal Closure) 포함.

  1. μƒνƒœ: WebSocket 계측은 OPEN β†’ CLOSING μƒνƒœλ‘œ μ§„μž…ν•©λ‹ˆλ‹€.

OPEN μƒνƒœμ—μ„œ ν•œμͺ½μ΄ Close Frame을 보내면 κ·Έ μˆœκ°„λΆ€ν„° ν•΄λ‹Ή WebSocket κ΅¬ν˜„μ€ CLOSING으둜 λ“€μ–΄κ°€κ³ , 응닡 CLOSEλ₯Ό 주고받은 λ’€ CLOSED둜 μ΄λ™ν•©λ‹ˆλ‹€.

즉, 이 μ‹œμ μ—μ„œ μ„œλ²„ WebSocket μƒνƒœλŠ” OPEN β†’ CLOSING으둜 μ „μ΄λ˜κ³ , ν΄λΌμ΄μ–ΈνŠΈμ˜ 응닡을 κΈ°λ‹€λ¦½λ‹ˆλ‹€.

[Packet-322]: Client β†’ Server (ACK)

ν΄λΌμ΄μ–ΈνŠΈ OSκ°€ TCP κ³„μΈ΅μ—μ„œ Close Frame 데이터가 μœ μ‹€ 없이 λ„μ°©ν–ˆμŒμ„ ν™•μΈν•˜κ³  ACK νŒ¨ν‚·μ„ μ „μ†‘ν•©λ‹ˆλ‹€. μ΄λŠ” Application Layer의 응닡이 μ•„λ‹ˆλΌ, L4 μˆ˜μ€€μ˜ μˆ˜μ‹  확인 λ©”μ»€λ‹ˆμ¦˜μž…λ‹ˆλ‹€.

  • ACKλŠ” TCP 레벨의 μ‹ λ’°μ„± 보μž₯ κ³Όμ •

[Packet-324]: Client β†’ Server (WebSocket Connection Close [FIN])

λΌμ΄μ–ΈνŠΈκ°€ μ’…λ£Œ μš”μ²­μ„ μŠΉμΈν•˜κ³ , 이에 λŒ€ν•œ μ‘λ‹΅μœΌλ‘œ μžμ‹ μ˜ μ’…λ£Œ ν”„λ ˆμž„(Close Frame)을 μ „μ†‘ν•©λ‹ˆλ‹€. μ΄λŠ” μ„œλ²„ Close μš”μ²­μ— λŒ€ν•œ 응닡이며 Close Echo라고도 ν‘œν˜„λ©λ‹ˆλ‹€.

이 Close Frame을 μ†‘μ‹ ν•œ ν΄λΌμ΄μ–ΈνŠΈμ˜ WebSocket μƒνƒœ μ—­μ‹œ OPNE β†’ CLOSING으둜 μ „μ΄λ©λ‹ˆλ‹€.

ν”„λ ˆμž„ ꡬ쑰:

  • Mask=1: ν΄λΌμ΄μ–ΈνŠΈ β†’ μ„œλ²„ μ „μ†‘μ΄λ―€λ‘œ λ§ˆμŠ€ν‚Ή 적용

  • Opcode=0x8: μ—°κ²° μ’…λ£Œ μš”μ²­

  • FIN bit=1: WebSocket Frame μ’…λ£Œ

[Packet-325]: Server β†’ Client (ACK)

μ„œλ²„ TCP κ³„μΈ΅μ—μ„œ ν΄λΌμ΄μ–ΈνŠΈμ˜ Close Frame이 μ„±κ³΅μ μœΌλ‘œ λ„μ°©ν–ˆμŒμ„ ν™•μΈν•˜λ©°, μˆ˜μ‹ μ„ ν™•μΈν•˜κ³  ACKλ₯Ό μ „μ†‘ν•©λ‹ˆλ‹€.

이 μ‹œμ μ—μ„œ L7 레벨(WebSocket)의 논리적 연결은 μ•ˆμ „ν•˜κ²Œ μ’…λ£Œλ˜μ—ˆκ³ , 이후 TCP FIN κ΅ν™˜μ„ 톡해 Socketκ³Ό 같은 물리적 λ¦¬μ†ŒμŠ€κ°€ ν•΄μ œλ©λ‹ˆλ‹€.

Phase 5. TCP Connection Termination (Teardown)

TCP μ—°κ²° μ’…λ£ŒλŠ” FIN 기반의 μ’…λ£Œ 절차λ₯Ό 톡해 μ†ŒμΌ“(Socket) λ¦¬μ†ŒμŠ€ 및 포트 바인딩을 OS에 λ°˜ν™˜ν•©λ‹ˆλ‹€.

μΌλ°˜μ μœΌλ‘œλŠ” 4-Way Handshakeλ₯Ό μˆ˜ν–‰ν•˜μ§€λ§Œ, 상황에 따라 FIN + ACKκ°€ 합쳐져 3-Way처럼 λ³΄μ΄λŠ” μ΅œμ ν™”κ°€ λ°œμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이 μ˜ˆμ‹œμ—μ„œλŠ” 일반적인 4‑Way μ’…λ£Œκ°€, FINκ³Ό ACKλ₯Ό λ¬Άμ–΄μ„œ λ³΄λ‚΄λŠ” ν˜•νƒœλ‘œ 3‑Way처럼 μ΅œμ ν™”λœ μΌ€μ΄μŠ€μž…λ‹ˆλ‹€.

Full-Duplex(전이쀑) 연결을 ν•΄μ œν•˜λŠ” κ³Όμ •μž…λ‹ˆλ‹€.

  1. Server Output Close: 326번 νŒ¨ν‚·μœΌλ‘œ μ„œλ²„μ˜ 솑신 채널이 λ‹«ν˜”μŠ΅λ‹ˆλ‹€.

  2. Client Output Close: 327번 νŒ¨ν‚·μœΌλ‘œ ν΄λΌμ΄μ–ΈνŠΈμ˜ 솑신 채널이 λ‹«ν˜”μŠ΅λ‹ˆλ‹€.

  3. Complete Teardown: 328번 νŒ¨ν‚·μœΌλ‘œ μ–‘μͺ½μ˜ μƒνƒœκ°€ λ™κΈ°ν™”λ˜λ©° μ„Έμ…˜μ΄ μ™„μ „νžˆ μ’…λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€.

[Packet-326]: Server β†’ Client (FIN, ACK)

  1. μ„œλ²„κ°€ Active Closeλ₯Ό μ‹œλ„ν•˜λ©° λ¨Όμ € FIN을 μ „μ†‘ν•©λ‹ˆλ‹€.

ν”Œλž˜κ·Έ:

  • FIN=1:더 이상 보낼 데이터가 μ—†μŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€.

  • ACK=1: μ΄μ „κΉŒμ§€ μˆ˜μ‹ ν•œ 데이터λ₯Ό μ •μƒμ μœΌλ‘œ ν™•μΈν–ˆμŒμ„ μ˜λ―Έν•©λ‹ˆλ‹€.

  1. μƒνƒœ 전이 μ„œλ²„λŠ” ESTABLISHED β†’ FIN_WAIT_1 μƒνƒœλ‘œ μ§„μž…ν•©λ‹ˆλ‹€.

이 μ‹œμ μ—μ„œ μ„œλ²„λŠ” ν΄λΌμ΄μ–ΈνŠΈμ˜ ACKλ₯Ό 기닀리고 있으며, 이후 ν΄λΌμ΄μ–ΈνŠΈμ˜ FIN을 λ³„λ„λ‘œ μˆ˜μ‹ ν•΄μ•Ό ν•©λ‹ˆλ‹€.

[Packet-327]: Client β†’ Server (FIN, ACK)

  1. ν΄λΌμ΄μ–ΈνŠΈκ°€ Passive Closeλ₯Ό μˆ˜ν–‰ν•©λ‹ˆλ‹€. μ„œλ²„μ˜ FIN에 λŒ€ν•œ ACK와 μžμ‹ μ˜ FIN을 ν•©μ³μ„œ μ „μ†‘ν•©λ‹ˆλ‹€.

μ„œλ²„μ˜ FIN에 λŒ€ν•œ ACK와 μžμ‹ μ΄ 보낼 FIN을 ν•˜λ‚˜μ˜ μ„Έκ·Έλ¨ΌνŠΈμ— ν•©μΉœ μ΅œμ ν™”λœ νŒ¨ν„΄μž…λ‹ˆλ‹€.

이 λ™μž‘μœΌλ‘œ 인해 4-Wayκ°€ 3-Way처럼 λ³΄μ΄λŠ” ν˜•νƒœκ°€ λ©λ‹ˆλ‹€.

ν”Œλž˜κ·Έ:

  • FIN=1: ν΄λΌμ΄μ–ΈνŠΈλ„ 더 이상 보낼 데이터가 μ—†μŒ

  • ACK=1: μ„œλ²„ FIN에 λŒ€ν•œ 확인

  1. μƒνƒœ 전이:

πŸ’‘ 일반적으둜 CLOSE_WAITμ—μ„œλŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ λ§ˆμ§€λ§‰μœΌλ‘œ writeλ₯Ό μˆ˜ν–‰ν•  수 μžˆλŠ” 기회λ₯Ό μ£Όμ§€λ§Œ, μ—¬κΈ°μ„œλŠ” 남은 데이터가 μ—†κΈ° λ•Œλ¬Έμ— λ°”λ‘œ FIN

  • ν΄λΌμ΄μ–ΈνŠΈλŠ” ESTABLISHED β†’ CLOSE_WAITλ₯Ό 거쳐 μ¦‰μ‹œ LAST_ACK μƒνƒœκ°€ λ©λ‹ˆλ‹€.

    • μ¦‰μ‹œ FIN을 λ³΄λ‚΄λ―€λ‘œ CLOSE_WAITλ₯Ό κ±°μΉ˜μ§€ μ•Šκ³  LAST_ACK μƒνƒœλ‘œ μ§„μž…ν•©λ‹ˆλ‹€.

  • μ„œλ²„λŠ” 이 νŒ¨ν‚·(ACK)을 λ°›κ³  FIN_WAIT_2둜 κ°”λ‹€κ°€, λ™μ‹œμ— λ“€μ–΄μ˜¨ FIN을 μ²˜λ¦¬ν•˜λ©° TIME_WAIT μƒνƒœλ‘œ μ§„μž…ν•©λ‹ˆλ‹€.

    • ν΄λΌμ΄μ–ΈνŠΈ ACK μˆ˜μ‹  β†’ FIN_WAIT_2

    • ν΄λΌμ΄μ–ΈνŠΈ FIN μˆ˜μ‹  β†’ TIME_WAIT

    • λ™μ‹œμ— 두 이벀트λ₯Ό μ²˜λ¦¬ν•˜κΈ° λ•Œλ¬Έμ— 쀑간 μƒνƒœκ°€ μˆœμ‹κ°„μ— λ³€κ²½λ©λ‹ˆλ‹€.

TCP μŠ€νƒ κ΅¬ν˜„μ— 따라 쀑간 μƒνƒœλ₯Ό μ–΄λ–»κ²Œ μ—…λ°μ΄νŠΈν•˜λŠ”μ§€ 둜그 μƒμ—μ„œλŠ” 잘 보이지 μ•Šμ„ 수 μžˆμ§€λ§Œ,

논리 흐름은 FIN_WAIT_1 β†’ (ACK) β†’ FIN_WAIT_2 β†’ (FIN) β†’ TIME_WAIT μž…λ‹ˆλ‹€.

[Packet-328]: Server β†’ Client (ACK)

  1. μ„œλ²„κ°€ ν΄λΌμ΄μ–ΈνŠΈ FIN에 λŒ€ν•œ μ΅œμ’… 확인(ACK)λ₯Ό μ „μ†‘ν•˜λ©° μ’…λ£Œ 절차λ₯Ό λ§ˆλ¬΄λ¦¬ν•©λ‹ˆλ‹€.

  2. μƒνƒœ 전이:

    • ν΄λΌμ΄μ–ΈνŠΈλŠ” LAST_ACK β†’ CLOSED μƒνƒœκ°€ λ˜μ–΄ μ¦‰μ‹œ μ†ŒμΌ“ λ¦¬μ†ŒμŠ€λ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

    • μ„œλ²„λŠ” TIME_WAIT μƒνƒœλ₯Ό μœ μ§€(μ§€μ—° νŒ¨ν‚· 처리 보μž₯)ν•œ ν›„ CLOSED λ©λ‹ˆλ‹€.

      • μ§€μ—°λœ μ„Έκ·Έλ¨ΌνŠΈ μ†Œκ±°

      • 이전 μ—°κ²°μ˜ μ„Έκ·Έλ¨ΌνŠΈκ°€ μƒˆλ‘œμš΄ μ—°κ²°λ‘œ ν˜Όμž…λ˜μ§€ μ•Šλ„λ‘ 보μž₯

Last updated