TCP상에서 HTTP 뜯어보기: HTTP Message

2025. 10. 22. 14:35·네트워크

tcp/ip 4계층의 관점에서 http는 tcp 상에 구현된 프로토콜이다.

이번에 rtd에 필요한 소켓 통신을 구현하기 위해 TCP를 파다 보니 문득 tcp서버에서도 http요청을 다룰 수 있을 것이라는 생각이 들었다. 그래서 브라우저에서 내 TCP서버 주소로 GET 요청을 보내봤다.

GET / HTTP/1.1
Host: localhost:52536
Connection: keep-alive
Cache-Control: max-age=0
sec-ch-ua: "Whale";v="3", " Not;A Brand";v="99", "Chromium";v="106"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.5249.114 Whale/3.17.145.12 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7

받은 패킷을 문자열로 변환해보니 이런 HTTP헤더가 나왔다. HTTP는 평문으로 데이터를 보낸다는 말이 이거였구만
http메소드와 자주 건드리게 되는 몇 가지의 헤더는 chrome devtools, postman, curl ...등등에서 쉽게 접하기 때문에 익숙하지만 HTTP메시지 전체의 원형은 이번에 처음 접해보았다.

그리고 이 때 tcp서버의 콘솔에서 눈길을 끈 점이 하나 있는데, 브라우저에서 시작된 소켓 연결은 패킷전송이 종료됨과 동시에 끊겼다.
이게 바로 HTTP의 특징인 비연결성(Connectionless), 무상태성(Stateless)이다.

  1. 연결 초기화(3-way-handshake)
  2. 요청이 담긴 패킷을 서버로 송신
  3. 응답이 담긴 패킷을 서버로부터 수신
  4. 연결 종료(4-way-handshake)
    라는 과정을 방금 거친 것이다.

계속해서, GET요청은 헤더만 있고 바디는 없다.
바디도 확인해보기 위해 POST도 보내봤다.
postman을 썼더니 위의 GET에서 보이던 브라우저정보에 대한 헤더라든지 여러 헤더들이 사라진 것이 보인다.

POST / HTTP/1.1
User-Agent: PostmanRuntime/7.29.2
Accept: */*
Postman-Token: 85d4ac69-2a4d-456b-81d7-dda594b2cd6c
Host: localhost:52536
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 17

network-test=test

Content-Type이라는 아주 눈에 익은 헤더 하나가 눈에 보인다.

그 아래에 있는 Content-Length라는 친구는 payload의 길이를 정의하고있다.

아래는 MDN(mozilla developer network)
에 있는 HTTP 메시지에 대한 글을 인용한 것이다.

HTTP 메시지

  1. 시작 줄(start-line)에는 실행되어야 할 요청, 또은 요청 수행에 대한 성공 또는 실패가 기록되어 있습니다. 이 줄은 항상 한 줄로 끝납니다.
  2. 옵션으로 HTTP 헤더 세트가 들어갑니다. 여기에는 요청에 대한 설명, 혹은 메시지 본문에 대한 설명이 들어갑니다.
  3. 요청에 대한 모든 메타 정보가 전송되었음을 알리는 빈 줄(blank line)이 삽입됩니다.
  4. 요청과 관련된 내용(HTML 폼 콘텐츠 등)이 옵션으로 들어가거나, 응답과 관련된 문서(document)가 들어갑니다. 본문의 존재 유무 및 크기는 첫 줄과 HTTP 헤더에 명시됩니다.

아까 실제 받았던 데이터와 맞아떨어지는 것을 확인할 수 있다.

이번에는 HTTP 응답에 대한 인용이다.

HTTP 응답

HTTP 응답의 시작 줄은 상태 줄(status line)이라고 불리며, 다음과 같은 정보를 가지고 있습니다.

  1. 프로토콜 버전: 보통 HTTP/1.1입니다.
  2. 상태 코드: 요청의 성공 여부를 나타냅니다. [200] [404] 혹은 [302]입니다.
  3. 상태 텍스트: 짧고 간결하게 상태 코드에 대한 설명을 글로 나타내어 사람들이 HTTP 메시지를 이해할 때 도움이 됩니다.

상태 줄은 일반적으로 HTTP/1.1 404 Not Found. 같이 생겼습니다.

이를 토대로 HTTP 응답메시지를 짜보았다.

HTTP/1.1 200 OK
Content-Length: 53
Content-Type: text/html

<html>
<body>
<h1>안녕 HTTP!!!</h1>
</body>
</html>

위와 같은 HTTP메시지를 담은 패킷을 내 TCP서버에 연결한 소켓에게 전송하도록 하였다.

그 결과

전송하고자 하는 바가 전달된 것 같지만 뭔가 문제가 있다.
인코딩을 알리는 헤더가 없기 때문에 문자타입이 맞지않아 한글이 박살났다.
Content-Type 헤더를 추가해주자. 캐릭터셋=utf8

Content-Type: text/html; charset=UTF-8

ㅎㅇ!!
이로써 TCP 통신을 통해 안녕 HTTP!!! 라는 Static Web Page를 전송하는 HTTP서버를 구현한 것이 되었다.

이번에는 가변길이 패킷을 실제로 Content-Length로 처리하는 것을 확인하려고
Content-Length를 실제 본문(53byte)보다 더 크게 해서(100byte) 보내봤다.

HTTP/1.1 200 OK
Content-Length: 100
Content-Type: text/html; charset=UTF-8

<html>
<body>
<h1>안녕 HTTP!!!</h1>
</body>
</html>

그 결과

빨간 동그라미친 부분을 보면
페이지 로드가 완료되지 않았고,
devtools의 network탭에서는 (pending) 상태로
나머지 패킷이 들어오기를 기다린다!

반대로 Content-Length를 실제 본문보다 작게하면

</
HTML 뒷부분의 닫는 태그쪽이 수신되지 못했다. 그래서 태그로 인식되지 못하고 그냥 텍스트로 표현됐다.

이처럼 Content-Length에 정해진 크기를 초과하는 데이터는 버려졌다.


유익한 삽질이었다. HTTP가 어떤식으로 굴러가는지를 직접 만져볼 수 있었다.

'네트워크' 카테고리의 다른 글

[HTTP 보안] JWT 저장 방식별 장단점  (0) 2026.01.23
'네트워크' 카테고리의 다른 글
  • [HTTP 보안] JWT 저장 방식별 장단점
devracoon
devracoon
  • devracoon
    개발하는 너굴맨
    devracoon
  • 전체
    오늘
    어제
    • 분류 전체보기 (10) N
      • 개발 (6)
      • 언어&프레임워크 (0)
      • 자료구조&알고리즘 (1)
      • 컴퓨터구조 (0)
      • 데이터베이스 (0)
      • 네트워크 (2) N
      • 클라우드컴퓨팅 (0)
      • 티스토리 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    티스토리
    docker
    short-url
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
devracoon
TCP상에서 HTTP 뜯어보기: HTTP Message
상단으로

티스토리툴바