프로토콜
어릴때 컴퓨터 공부할때는 프로토콜을 그냥 "약속" 이라고만 배웠다.
약속
당시 컴퓨터 선생님들도 본인들이 이해를 하고 알려주기보다는 그냥 암기한대로 알려주는것 같았고, 아무리 이해해보려 해도 당최 그래서 그 약속을 통해 뭘 하는건지 알수가 없어서 많이 답답했던 기억이 있다.
지금와서 문득 과거의 나를 이해시킨다는 생각으로 글을 써본다.
현대 환경에서 쓰이는 프로토콜 중 가장 유명한 것이 HTTP일것이다.
무엇의 약자인지 같은 사전적인 건 제외하고 이 프로토콜이 어떻게 작동하는지 직접 프로토콜을 사용해서 데이터의 송수신을 해보자.
HTTP요청 작성
HTTP를 직접 작성하려면 소켓통신을 통해 요청전문을 작성할수 있다.
여기서 요청전문이라 함은 "HTTP라는 프로토콜" 즉 과거 컴퓨터 선생님들이 말하던 그 "약속"에 따라 작성된 문서이다.
예를들면 첫번째 줄에는 이런정보가 들어가고 두번째 줄에는 이런정보가 들어감
아래는 특정 HTTP서버에 루트 문서를 요청하는 간단한 요청전문이다.
GET / HTTP/1.1
이 요청을 작성해서 원하는 HTTP서버로 전달하면 되는데, 구글의 HTTP서버로 전달하면 구글의 루트 문서를 반환할것이고, 네이버로 전달하면 네이버의 루트 문서를 반환하게 된다.
그리고 이를 간단히 할수 있는 방법은 텔넷을 사용하는것이다.
telnet google.com 80
위 명령어를 통해 google.com서버로 소켓연결을 하며, 연결이 완료된 후 요청을 작성하면 된다.
위 명령어는 telnet을 통해 google.com 서버의 80번 포트로 접속 한다는 뜻인데 80번 포트인 이유는 HTTP가 일반적으로 80번 포트를 사용하기 때문인데, 경우에 따라서 서버관리자가 원치 않는 경우 80번 포트가 아닌 다른 포트를 사용하기도 한다.
GET / HTTP/1.1[엔터]
[엔터]
위와같이 작성 하는데 반드시 엔터를 두번 쳐야 한다.
왜냐하면 HTTP프로토콜에 "개행문자 두개가 연속으로 나오면 문서가 종료된것이다" 라고 약속되어있기 때문이고 엔터가 바로 개행문자이기 때문.
위와같이 했다면 HTML코드를 응답했을 것이다.
여기까지 HTTP를 따라 요청을 하고 응답을 받는 사이클을 완료했다.
웹브라우저에 구글에 접속하면 웹브라우저는 위와같은 요청및 응답을 처리해주고 결과를 보여주는것으로 이해할수 있다.
분석
자세한 설명은 MDN | An overview of HTTP 에서 확인할 수 있으나 위에서 작성한 요청을 분석하자면 다음과 같다.
GET
은 GET메서드로 요청을 한다는것이며 의미적으로는 "문서를 받기위한 요청"이라고 볼수있다.- 공백문자는 "메서드 작성을 끝낸다"라는 뜻
- 공백문자 다음에 오는 곳에는 요청하는 문서의 위치를 적으면 되는데, 위 요청에서는
/
라고 썼으므로 "/
위치에 있는 문서를 줘라" 라고 적은것이다. - 다시 나오는 공백문자는 "문서의 위치작성을 끝낸다"라는 뜻
- 그다음 나오는
HTTP/1.1
은 HTTP버전에대한 명시다. HTTP버전에 따라 약속된 규칙이 다르기 때문에 본인이 작성하는 요청이 어떤 버전에 해당하는 규칙인지 확인후 적어주면 된다. - 이후 엔터가 연속 두번 나오는것은 "요청작성을 종료한다" 라는 뜻으로 엔터를 두번 친 순간 서버는 여태 작성된 요청전문을 HTTP규칙에 따라 해석한 후 요청한 문서를 반환하고 프로세스를 종료시킨다.
응용
HTTP요청을 전달하는것은 소켓통신을 통해서 전달하면 다 가능한데, 위에서는 telnet을 사용했으나 당연히 프로그래밍 언어를 사용해서도 가능하다.
아래는 python을 사용해서 위에서 telnet으로 요청한 전문을 그대로 구현한 것이다.
import socket
def make_http_request():
# 소켓 생성
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
sock.connect(('www.google.com', 80))
# HTTP GET 요청 생성
request = (
"GET / HTTP/1.1\r\n"
"Host: www.google.com\r\n"
"User-Agent: Python Socket Client\r\n"
"Accept: text/html\r\n"
"Connection: close\r\n"
"\r\n"
)
# 요청 전송
sock.send(request.encode())
# 응답 수신
response = b''
while True:
data = sock.recv(4096)
if not data:
break
response += data
# 응답 디코딩 및 출력
decoded_response = response.decode('utf-8', errors='ignore')
return decoded_response
except Exception as e:
print(f"에러 발생: {e}")
return None
finally:
# 소켓 닫기
sock.close()
if __name__ == "__main__":
response = make_http_request()
print(response)
HTTP 그리고 SSL
과거에는 HTTP를 그대로 사용했으나 최근에는 중간에 데이터를 가로채는 등 해킹에대한 위협으로 인해 암호화된 통신을 사용하기 때문에, 일반적인 HTTP통신을 하지 않고 SSL위에서 HTTP통신을 하며 이를 HTTPS라고 칭한다.
SSL은 다른 문서에서 다루고 여기서는 간단히 HTTPS를 telnet비슷하게 사용할수 있는 방법만 다루도록 한다.
openssl s_client -connect google.com:443
위 명령어가 telnet google.com 80
의 SSL버전이다.
openssl은 암호화 소프트웨어이고 내장된 기능이 여러개 있는데 그중에 s_client는 SSL을 통한 접속을 지원하는 기능이다.
즉, SSL을 통해 google.com의 443포트로 접속을 한것인데 마찬가지로 HTTP가 80번 포트를 주로 쓰듯 HTTPS는 443포트를 주로 쓰며 서버관리자가 원하는 경우 443이 아닌 다른포트를 사용하기도 한다.
접속이 완료되면 똑같이 HTTP요청 전문을 작성해서 전달하면 된다.
GET / HTTP/1.1[엔터]
[엔터]