티스토리 뷰

728x90
반응형

요즘은 많은 분들이 Django나 Flask, Spring등의 웹프래임워크를 사용해서 손쉽게 Web App을 제작할 수 있습니다.

일반적으로 이 프래임워크 내에서는 Requests라는 라이브러리를 지원하며, 이 라이브러리를 이용해 다른 기기로 Requests를 보내거나 Reponse를 받아 처리하게 됩니다.

 

저도 이런 것들을 이용하면서, 궁금증이 생겼습니다.

"도대체 이 Requests라는건 어떻게 동작하는것인가?"

 

이번 포스팅에서는 HTTP통신에 대한 간단한 이야기와, HTTP통신을 Requests같은 라이브러리 없이 Socket Level로 사용하는 방법에 대해서 다룹니다.

1. HTTP

HTTP는 Hyper Text Transfer Protocol의 약자로, Hyper Text를 전달하는 방법에 대한 약속이라고 볼 수 있습니다.

HTTP Wikipedia

현재 거의 상당수의 Web app은 HTTP 통신을 통해서 접속, 서비스 됩니다.

이러한 HTTP는 1991년 HTTP0.9를 시작으로, 현재 HTTP 2.0까지 공식적으로 존재하며 HTTP 3.0이 준비 중 입니다.

HTTP의 Protocol에는

  1. HTTP요청(Requests)을 보낼 위치
  2. HTTP요청에 포함될 정보(Message)
  3. HTTP요청의 종류(Methods)
  4. HTTP요청에 대한 반응(Response) + 상태 코드

등이 포함됩니다.

HTTP에 대한 상세 내용은 아래 MDN문서를 통해서 더 자세히 알 수 있습니다.

MDN HTTP Docs

2. TCP/IP

HTTP의 의 Hyper Text는 TCP/IP 계층을 통해서 기기간 전송됩니다.

TCP/IP를 이용하면

  1. 오류가 없이 데이터가 전송
  2. 순서가 뒤집히는 일 없이 전송
  3. 조각나지 않는 데이터 스트림

을 약속받을 수 있기 때문에, 현재 HTTP통신에서 사용됩니다.

3. Hyper Text의 예제

Hyper Text의 내용은 크게 3개로 구성됩니다.

  1. Hyper Text Method, 요청 URI, 버전
  2. Hyper Text Header
  3. Entity 본문

아래 예시를 보시죠

#3_1 부분
GET /wcslog.js HTTP/1.1

#3_2. Header 부분
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ko,en;q=0.9,en-US;q=0.8
Connection: keep-alive
Host: wcs.naver.net
If-Modified-Since: Tue, 20 Jul 2021 07:31:20 GMT
If-None-Match: "60f67bc8-4e86"
Referer: https://devocean.sk.com/
Sec-Fetch-Dest: script
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="101", "Microsoft Edge";v="101"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"

#3_3. Entity 본문 파트

(Post형식으로 Enity 본문이 있는것을 찾으려 했는데, 쉽지가 않네요 :(.. )

 

위 예시는 DevOcean의 Main Page에 접속할 경우 Client의 인터넷 브라우져에서 DevOcean의 서버쪽으로 요청을 보내는 HTTP 메세지 입니다.

그러면 서버 쪽에서는 해당 HTTP 요청을 분석한 다음 Client로 HTTP 형식의 응답을 보내줍니다.

이렇게 서버<->Client 사이에 HTTP 메세지를 주고받으며 통신이 이뤄 집니다.

4. HTTP를 어떻게 전달하는가?

TCP/IP 통신을 이용한다고 하였지만, TCP/IP 통신을 직접 Contorol하는 프로그래밍을 저는 사용해 본 적은 없습니다.

대신, Window 기준으로 System Call 이전의 Low Level 통신 방법으로 Socket 프로그래밍을 지원합니다.

 

이 Socket 프로그래밍을 이용하면, 드디어 기초적인 HTTP 통신이 가능해 집니다.

5. Socket을 이용한 HTTP 예제

Socket 프로그래밍은 TCP/IP통신은 운영체제 Level에서 지원합니다.

덕분에 Requests와 같은 라이브러리 없이 Socket만을 이용해서 HTTP 통신이 가능합니다.

 

아래는 위 HTTP 예제를 Socket을 사용해서 통신하는 예제 입니다.

import socket

temp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#DNS Name(wcs.naver.net/wcslog.js의 Host Name)
#의 IP주소를 입력
temp_socket.connect(('23.218.150.234', 80))

#실제로 Socket을 통해서 전달할 HTTP 메세지
http_text = '''
GET /wcslog.js HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ko,en;q=0.9,en-US;q=0.8
Connection: keep-alive
Host: wcs.naver.net
If-Modified-Since: Tue, 20 Jul 2021 07:31:20 GMT
If-None-Match: "60f67bc8-4e86"
Referer: https://devocean.sk.com/
Sec-Fetch-Dest: script
Sec-Fetch-Mode: no-cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36 Edg/101.0.1210.53
sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="101", "Microsoft Edge";v="101"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "Windows"

'''
#주의 Header와 Entity Data 사이에는 Break Line이 꼭 필요
temp_socket.send(http_text.encode())
print("send end")

data = temp_socket.recv(1024)
print("data recv end")
print(data.decode())
'''
send end

data recv end

#socket을 통해서 받아온 HTTP Response
#304 Response를 통해서 현재 요청은 사용자 PC에 캐시되어서, 캐시로 Redirect를 하라고 Response가 온 것을 볼 수 있음
HTTP/1.1 304 Not Modified
Last-Modified: Tue, 20 Jul 2021 07:31:20 GMT
ETag: "60f67bc8-4e86"
Server: nginx
Content-Type: application/javascript
Accept-Ranges: bytes
Vary: Accept-Encoding
Cache-Control: max-age=2560
Expires: Mon, 23 May 2022 08:33:57 GMT
Date: Mon, 23 May 2022 07:51:17 GMT
Connection: Keep-Alive
Content-Encoding: gzip
Age: 62
'''

아주 정상적으로 HTTP 통신을 한 것을 볼 수 있습니다. (물론 Redirect를 해야하는 부분을 알아서 처리하지는 못합니다)

위와같은 HTTP Requests는 인터넷 브라우저에서 보내게 되며, 30X형태의 Redirect처리는 브라우저에서 알아서 처리해준다고 볼 수 있습니다.

6.그럼 웹서버는?

웹서버 역시 Socket으로 만드는게 가능 합니다. HTTP 메세지를 Socket_Server를 통해서 받고, HTTP 메세지를 어떤 식으로 처리할 지 정리하면 됩니다.

 

아래는 간단한 Socket HTTP 처리 예제입니다!

import socket

temp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#Web Server IP주소를 Bind
temp_socket.bind(("10.145.71.68", 24242))
#지속적으로 연결을 확인하는 Listener 생성
temp_socket.listen()
conn, addr = temp_socket.accept()
data = conn.recv(1024*4).decode()
#요청에 따라 돌려줄 Response 생성
ret_data = """
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Accept-Ranges: bytes
Vary: Accept-Encoding

<!DOCTYPE html><html><body><h2>Hello World</h2></body></html>
"""
conn.send(ret_data.encode())
conn.close()
print("send end")

결과 웹 브라우저를 통해서 서버에 접근하고, 정상적으로 Response를 받아오는 것을 알 수 있습니다 :)

정리하기

  1. 웹서버 프래임워크의 밑단에는 HTTP 통신이 있다.
  2. HTTP 통신은 Socket 프로그래밍으로 가능하다.
  3. 원한다면 Socket 프로그래밍으로 새로운 웹서버 프래임워크를 만들 수 있다.

제가 궁금해서 시작한 내용인데, 혹시 저 말고도 같은 궁금증이 있었을 분들에게 도움이 되었기를 바랍니다 :)

 

감사합니다.



728x90
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함