프로그래밍공부(Programming Study)/네트워크(Network)

웹 애플리케이션 프로토콜: HTTP부터 gRPC까지

Chaany 2024. 8. 13.
728x90

웹 애플리케이션은 다양한 프로토콜을 통해 서버와 클라이언트 간의 통신을 가능하게 하고 데이터를 주고받습니다. 이 글에서는 웹 애플리케이션 개발에서 자주 사용되는 HTTP, HTTPS, WebSocket, SOAP, REST, GraphQL, RPC, gRPC 등의 주요 프로토콜에 대해 살펴보고, 각 프로토콜의 개념, 특징, 장단점, 그리고 파이썬으로 구현한 코드 예시를 통해 어떻게 사용하는지 알아보겠습니다.


1. HTTP (HyperText Transfer Protocol)

개념:
HTTP는 웹에서 데이터를 주고받기 위한 가장 기본적인 프로토콜입니다. 클라이언트가 서버에 요청을 보내고, 서버가 응답하는 클라이언트-서버 모델을 기반으로 합니다. 웹 페이지 로딩, API 호출 등에 사용됩니다.

특징:

  • 요청-응답 구조: 클라이언트가 요청을 보내면 서버가 응답합니다.
  • 무상태성: 각 요청은 독립적이며, 서버는 이전 요청의 상태를 기억하지 않습니다.

장점:

  • 간단하고 보편적: 전 세계 모든 웹 브라우저와 서버에서 기본적으로 지원됩니다.
  • 가벼운 구조: 요청과 응답이 비교적 간단하여 빠르게 처리됩니다.

단점:

  • 보안 취약성: HTTP 자체로는 데이터가 암호화되지 않기 때문에, 전송 중에 데이터가 가로채질 위험이 있습니다.

사례: 웹 페이지 로딩, RESTful API의 데이터 전송.

코드 예시:

import requests

# HTTP GET 요청
response = requests.get('http://jsonplaceholder.typicode.com/posts')
print(response.status_code)  # 상태 코드 출력
print(response.json())  # 응답 JSON 데이터 출력

2. HTTPS (HTTP Secure)

개념:
HTTPS는 HTTP에 SSL/TLS 암호화가 추가된 프로토콜로, 데이터 전송 중 보안을 제공합니다. 민감한 정보를 전송할 때 사용하는 필수적인 프로토콜입니다.

특징:

  • 암호화: SSL/TLS를 통해 클라이언트와 서버 간의 통신을 암호화합니다.
  • 인증서 기반: 서버는 SSL/TLS 인증서를 통해 클라이언트에게 자신의 신원을 증명합니다.

장점:

  • 보안 강화: 데이터가 암호화되어 전송되므로 도청, 변조 등의 공격으로부터 보호할 수 있습니다.
  • 신뢰성: 사용자의 데이터 보호와 관련된 신뢰성을 제공합니다.

단점:

  • 복잡성 증가: SSL/TLS 인증서의 발급 및 설정이 추가로 필요합니다.
  • 성능: 암호화/복호화 과정이 추가되어 성능이 약간 저하될 수 있습니다.

사례: 온라인 쇼핑, 금융 거래, 로그인 페이지 등 민감한 데이터를 다루는 모든 웹 서비스.

코드 예시:

response = requests.post('https://jsonplaceholder.typicode.com/posts', json={'title': 'foo', 'body': 'bar', 'userId': 1})
print(response.status_code)
print(response.json())

3. WebSocket

개념:
WebSocket은 클라이언트와 서버 간에 지속적인 양방향 통신을 가능하게 하는 프로토콜입니다. 이는 HTTP 연결을 업그레이드하여 사용되며, 실시간 애플리케이션에서 매우 유용합니다.

특징:

  • 양방향 통신: 연결이 맺어진 후 클라이언트와 서버는 양방향으로 데이터를 주고받을 수 있습니다.
  • 지속적 연결: 연결이 열려 있는 한 데이터 전송이 지속됩니다.

장점:

  • 실시간 데이터 전송: 실시간으로 데이터를 주고받을 수 있어 채팅, 게임, 실시간 알림 등에 적합합니다.
  • 효율성: HTTP에 비해 오버헤드가 적고, 빠른 데이터 전송이 가능합니다.

단점:

  • 복잡한 설정: HTTP와 다른 포트를 사용하며, 설정이 복잡할 수 있습니다.
  • 보안: HTTPS처럼 기본적인 보안 기능이 내장되어 있지 않기 때문에 별도의 보안 조치가 필요할 수 있습니다.

사례: 채팅 애플리케이션, 실시간 알림 시스템, 실시간 데이터 스트리밍.

코드 예시:

import asyncio
import websockets

async def hello():
    uri = "ws://echo.websocket.org"
    async with websockets.connect(uri) as websocket:
        await websocket.send("Hello WebSocket!")
        response = await websocket.recv()
        print(response)

asyncio.get_event_loop().run_until_complete(hello())

4. SOAP (Simple Object Access Protocol)

개념:
SOAP는 XML을 사용하여 구조화된 데이터를 교환하기 위한 프로토콜입니다. 주로 엔터프라이즈 애플리케이션에서 사용되며, 강력한 보안 및 트랜잭션 기능을 제공합니다.

특징:

  • XML 기반: 메시지를 XML 형식으로 주고받습니다.
  • 높은 신뢰성: 표준화된 구조로 다양한 플랫폼과 언어에서 호환성이 좋습니다.
  • 트랜잭션 지원: 복잡한 트랜잭션을 처리할 수 있는 기능을 제공합니다.

장점:

  • 강력한 보안: WS-Security 등의 표준을 통해 보안을 강화할 수 있습니다.
  • 표준화: WSDL(Web Services Description Language)을 통해 서비스 정의가 명확합니다.

단점:

  • 복잡성: XML을 사용하여 데이터가 무겁고, 개발 및 유지보수가 복잡합니다.
  • 오버헤드: 데이터 전송 시 많은 오버헤드가 발생할 수 있습니다.

사례: 대기업의 금융 서비스, ERP 시스템 통합, 정부 기관의 데이터 교환.

코드 예시:

from zeep import Client

# SOAP 클라이언트 생성
client = Client('http://www.dneonline.com/calculator.asmx?WSDL')

# SOAP 메서드 호출
result = client.service.Add(5, 3)
print(f"5 + 3 = {result}")

5. REST (Representational State Transfer)

개념:
REST는 웹 상에서 자원을 상태 없이 주고받기 위한 아키텍처 스타일입니다. HTTP 메서드(GET, POST, PUT, DELETE 등)를 사용하여 자원에 대한 CRUD(Create, Read, Update, Delete) 작업을 수행합니다.

특징:

  • 자원 기반: 모든 자원은 URI로 고유하게 식별됩니다.
  • 무상태성: 서버는 클라이언트의 상태를 저장하지 않으며, 모든 요청은 독립적입니다.
  • 다양한 표현 형식: JSON, XML 등 다양한 형식으로 데이터를 주고받을 수 있습니다.

장점:

  • 유연성: 다양한 클라이언트에서 사용할 수 있으며, HTTP를 기반으로 하기 때문에 광범위하게 지원됩니다.
  • 확장성: 서버와 클라이언트의 상호작용을 단순화하여 시스템 확장이 용이합니다.
  • 성능: 무상태성으로 인해 서버의 부하가 줄어들고, 캐시를 활용하여 성능을 최적화할 수 있습니다.

단점:

  • 트랜잭션 관리 어려움: 복잡한 트랜잭션을 관리하는 데 어려움이 있을 수 있습니다.
  • 실시간 기능 부족: 실시간 양방향 통신에는 적합하지 않습니다(이 경우 WebSocket을 사용).

사례: 대부분의 최신 웹 서비스(API)에서 RESTful API를 사용하여 데이터 및 서비스 제공.

코드 예시:

from flask import Flask, jsonify, request

app = Flask(__name__)

# 가상 데이터베이스
books = [
    {'id': 1, 'title': '1984', 'author': 'George Orwell'},
    {'id': 2, 'title': 'To Kill a Mockingbird', 'author': 'Harper Lee'}
]

@app.route('/books', methods=['GET'])
def get_books():
    return jsonify(books)

@app.route('/books', methods=['POST'])
def add_book():
    new_book = request.get_json()
    books.append(new_book)
    return jsonify(new_book), 201

if __name__ == '__main__':
    app.run(debug=True)

6. GraphQL

개념:
GraphQL은 API의 쿼리 언어로, 클라이언트가 필요한 데이터를 정확하게 요청하고, 서버는 그에 맞는 응답을 반환합니다. REST의 대안으로 사용되며, 클라이언트와 서버 간의

데이터 전송을 최적화할 수 있습니다.

특징:

  • 클라이언트 중심: 클라이언트가 필요한 데이터만 요청하고, 서버는 그에 맞게 데이터를 반환합니다.
  • 단일 엔드포인트: 모든 요청은 단일 엔드포인트를 통해 이루어지며, 다양한 리소스를 한 번에 요청할 수 있습니다.
  • 타입 시스템: 스키마를 통해 API의 데이터 구조를 명확히 정의할 수 있습니다.

장점:

  • 필요한 데이터만 반환: 클라이언트가 필요한 데이터만 정확히 요청할 수 있어, 불필요한 데이터 전송을 줄일 수 있습니다.
  • 유연성: 여러 리소스를 한 번에 요청할 수 있어, 여러 번의 API 호출을 줄일 수 있습니다.

단점:

  • 복잡성: 초기 설정과 학습이 다소 복잡할 수 있으며, 고도화된 쿼리는 서버 성능에 부담을 줄 수 있습니다.
  • 오버페칭과 언더페칭 문제: 잘못된 쿼리 구조로 인해 필요한 데이터보다 많은 데이터가 반환되거나, 필요한 데이터가 모두 반환되지 않을 수 있습니다.

사례: Facebook, GitHub, Shopify 등의 데이터 중심 서비스.

코드 예시:

from flask import Flask
from flask_graphql import GraphQLView
import graphene

class Book(graphene.ObjectType):
    id = graphene.Int()
    title = graphene.String()
    author = graphene.String()

class Query(graphene.ObjectType):
    books = graphene.List(Book)

    def resolve_books(self, info):
        return [
            Book(id=1, title='1984', author='George Orwell'),
            Book(id=2, title='To Kill a Mockingbird', author='Harper Lee')
        ]

schema = graphene.Schema(query=Query)

app = Flask(__name__)
app.add_url_rule('/graphql', view_func=GraphQLView.as_view('graphql', schema=schema, graphiql=True))

if __name__ == '__main__':
    app.run(debug=True)

7. RPC (Remote Procedure Call)

개념:
RPC는 원격 서버에서 프로시저(함수나 메소드)를 호출하는 프로토콜입니다. 이는 네트워크를 통해 서로 다른 시스템에서 프로시저 호출이 가능하게 합니다.

특징:

  • 함수 호출 방식: 클라이언트가 마치 로컬 함수처럼 서버의 함수를 호출할 수 있습니다.
  • 비동기/동기 호출: 비동기 및 동기 호출을 모두 지원하여, 클라이언트가 요청 결과를 기다리거나 바로 다음 작업을 수행할 수 있습니다.

장점:

  • 개발자 친화적: 개발자가 익숙한 함수 호출 형태로 API를 사용할 수 있습니다.
  • 간단한 통신: 클라이언트와 서버 간의 통신을 단순화합니다.

단점:

  • 플랫폼 종속성: 플랫폼 간 호환성이 제한될 수 있습니다.
  • 보안 이슈: RPC 호출은 네트워크를 통해 이루어지므로, 보안 문제가 발생할 수 있습니다.

사례: 분산 시스템에서의 데이터 처리, 원격 서버 관리.

코드 예시:

서버 코드:

from xmlrpc.server import SimpleXMLRPCServer

def add(x, y):
    return x + y

server = SimpleXMLRPCServer(("localhost", 8000))
print("Listening on port 8000...")
server.register_function(add, "add")
server.serve_forever()

클라이언트 코드:

import xmlrpc.client

with xmlrpc.client.ServerProxy("http://localhost:8000/") as proxy:
    result = proxy.add(5, 3)
    print(f"5 + 3 = {result}")

8. gRPC

개념:
gRPC는 Google에서 개발한 RPC 프로토콜로, HTTP/2를 기반으로 하며, Protobuf(Protocol Buffers)를 사용하여 데이터 직렬화를 합니다. gRPC는 고성능, 효율성, 멀티플렉싱을 지원하며, 마이크로서비스 아키텍처에서 자주 사용됩니다.

특징:

  • 양방향 스트리밍: 클라이언트와 서버 간의 양방향 데이터 스트리밍을 지원합니다.
  • HTTP/2 기반: 멀티플렉싱, 헤더 압축 등을 지원하여 성능을 최적화합니다.
  • Protobuf 사용: 데이터를 직렬화할 때 Protobuf를 사용하여 작은 데이터 크기와 높은 성능을 제공합니다.

장점:

  • 높은 성능: HTTP/2와 Protobuf의 조합으로 높은 성능을 제공합니다.
  • 다중 언어 지원: 다양한 프로그래밍 언어를 지원하여, 다양한 플랫폼에서 쉽게 사용할 수 있습니다.
  • 작은 데이터 크기: Protobuf를 사용하여 데이터를 직렬화하므로, 데이터 크기가 작고 효율적입니다.

단점:

  • 복잡한 설정: gRPC의 설정과 사용이 비교적 복잡하며, Protobuf 학습이 필요합니다.
  • 레거시 시스템과의 호환성: gRPC는 HTTP/2를 사용하기 때문에, 기존의 HTTP/1.x 기반 시스템과의 호환성이 제한될 수 있습니다.

사례: 마이크로서비스 아키텍처, 클라우드 서비스 간의 고성능 통신.

먼저, 프로토콜 버퍼(Protocol Buffers) 정의 파일 calculator.proto를 만듭니다:

syntax = "proto3";

service Calculator {
    rpc Add (AddRequest) returns (AddReply) {}
}

message AddRequest {
    int32 a = 1;
    int32 b = 2;
}

message AddReply {
    int32 result = 1;
}

서버 코드:

from concurrent import futures
import grpc
import calculator_pb2
import calculator_pb2_grpc

class CalculatorServicer(calculator_pb2_grpc.CalculatorServicer):
    def Add(self, request, context):
        return calculator_pb2.AddReply(result=request.a + request.b)

server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
calculator_pb2_grpc.add_CalculatorServicer_to_server(CalculatorServicer(), server)
server.add_insecure_port('[::]:50051')
server.start()
server.wait_for_termination()

클라이언트 코드:

import grpc
import calculator_pb2
import calculator_pb2_grpc

channel = grpc.insecure_channel('localhost:50051')
stub = calculator_pb2_grpc.CalculatorStub(channel)

response = stub.Add(calculator_pb2.AddRequest(a=5, b=3))
print(f"5 + 3 = {response.result}")

이 글에서 다룬 HTTP, HTTPS, WebSocket, SOAP, REST, GraphQL, RPC, gRPC 등의 웹 애플리케이션 프로토콜들은 각기 다른 용도로 사용되며, 상황에 맞게 선택하여 사용할 수 있습니다. 파이썬으로 구현한 코드 예시를 통해 각 프로토콜의 사용법을 이해하고, 실제 프로젝트에 적용해 보세요.

728x90

댓글