프로그래밍/Python

파이썬으로 배우는 네트워킹: 소켓 프로그래밍과 HTTP 클라이언트

shimdh 2025. 2. 22. 09:13
728x90

1. 소켓 프로그래밍: 클라이언트-서버 통신

소켓 프로그래밍은 네트워크를 통해 두 프로그램 간의 통신을 가능하게 하는 기술입니다. 주로 클라이언트-서버 모델을 기반으로 하며, 파이썬에서는 socket 모듈을 사용하여 간단하게 구현할 수 있습니다. 소켓 프로그래밍은 실시간 통신, 파일 전송, 채팅 애플리케이션 등 다양한 분야에서 활용됩니다.

1.1 소켓 프로그래밍의 기본 개념

  • 소켓(Socket): 네트워크 통신을 위한 연결 지점입니다. IP 주소와 포트 번호를 조합하여 고유한 식별자를 가집니다. 소켓은 TCP(Transmission Control Protocol)와 UDP(User Datagram Protocol) 두 가지 주요 프로토콜을 지원합니다.
  • 클라이언트(Client): 서버에 요청을 보내고 응답을 받는 역할을 합니다. 클라이언트는 서버의 IP 주소와 포트 번호를 알고 있어야 합니다.
  • 서버(Server): 클라이언트의 요청을 받아 처리하고 응답을 보내는 역할을 합니다. 서버는 특정 포트에서 클라이언트의 연결 요청을 기다립니다.

1.2 소켓 프로그래밍의 흐름

  1. 소켓 생성: socket.socket() 메소드를 사용하여 소켓 객체를 생성합니다. 이때, 소켓의 유형(예: TCP 또는 UDP)을 지정할 수 있습니다.
  2. 주소 바인딩: 서버는 특정 IP 주소와 포트에 바인딩합니다 (bind() 메소드). 이는 서버가 클라이언트의 연결 요청을 받을 준비가 되었음을 의미합니다.
  3. 리스닝: 서버는 클라이언트의 연결 요청을 기다립니다 (listen() 메소드). 이때, 동시에 처리할 수 있는 최대 연결 수를 지정할 수 있습니다.
  4. 연결 수락: 클라이언트의 연결 요청을 수락합니다 (accept() 메소드). 이 메소드는 클라이언트 소켓과 클라이언트 주소를 반환합니다.
  5. 데이터 송수신: 데이터를 주고받습니다 (send(), recv() 메소드). 데이터는 바이트 형식으로 전송되며, 문자열을 전송하려면 인코딩/디코딩이 필요합니다.
  6. 연결 종료: 통신이 끝나면 소켓을 닫습니다 (close() 메소드). 이는 리소스를 해제하고 연결을 종료하는 데 중요합니다.

1.3 실습 예제: TCP 서버와 클라이언트

TCP 서버 코드

import socket

# 1단계 - 소켓 생성
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2단계 - 주소 바인딩
server_address = ('localhost', 65432)  # localhost와 포트 번호 설정
server_socket.bind(server_address)

# 3단계 - 리스닝 시작
server_socket.listen(1)
print("서버가 대기 중입니다...")

while True:
    # 4단계 - 클라이언트 연결 수락
    client_socket, client_address = server_socket.accept()
    print(f"{client_address}에서 연결됨.")

    try:
        # 5단계 - 데이터 송수신
        while True:
            data = client_socket.recv(1024)
            if not data:
                break
            print(f"받은 메시지: {data.decode()}")
            response = f"메시지를 받았습니다 : {data.decode()}".encode()
            client_socket.sendall(response)

    finally:
        # 6단계 - 연결 종료
        client_socket.close()

TCP 클라이언트 코드

import socket

# 1단계 - 소켓 생성
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2단계 - 서버에 연결하기 
server_address = ('localhost', 65432)
client_socket.connect(server_address)

try:
    # 3단계 - 데이터 전송 
    message = "안녕하세요!"
    client_socket.sendall(message.encode())

    # 응답 받기 
    response = client_socket.recv(1024)
    print(f"서버로부터 받은 응답 : {response.decode()}")

finally:
    # 연결 종료 
    client_socket.close()

2. HTTP 클라이언트: 웹 서버와의 통신

HTTP(Hypertext Transfer Protocol)는 웹에서 데이터를 전송하기 위한 프로토콜입니다. 파이썬에서는 requests 라이브러리를 사용하여 HTTP 클라이언트를 쉽게 구현할 수 있습니다. HTTP 클라이언트는 웹 서버와의 상호작용을 통해 데이터를 가져오거나 전송하는 데 사용됩니다.

2.1 HTTP 프로토콜의 기본 개념

  • 요청(Request): 클라이언트가 서버에 특정 자원을 요청하는 메시지입니다. 요청 메소드(예: GET, POST, PUT, DELETE)를 통해 원하는 작업을 지정할 수 있습니다.
  • 응답(Response): 서버가 클라이언트의 요청에 대한 결과를 반환하는 메시지입니다. 응답에는 상태 코드(예: 200, 404)와 함께 데이터가 포함될 수 있습니다.

2.2 requests 라이브러리 사용하기

requests 라이브러리는 HTTP 요청을 간단하게 보낼 수 있도록 도와줍니다. 이 라이브러리는 RESTful API와의 상호작용, 웹 스크래핑, 데이터 수집 등 다양한 작업에 유용합니다.

설치 방법

pip install requests

GET 요청 예제

import requests

response = requests.get('https://api.example.com/data')
if response.status_code == 200:
    data = response.json()  # JSON 형식의 데이터 변환
    print(data)
else:
    print(f"Error: {response.status_code}")

POST 요청 예제

import requests

url = 'https://api.example.com/data'
payload = {'name': 'Alice', 'age': 30}
response = requests.post(url, json=payload)

if response.status_code == 201:
    print("Data created successfully!")
else:
    print(f"Error: {response.status_code}")

추가 기능: 헤더 설정 및 예외 처리

headers = {
    'Authorization': 'Bearer your_token_here',
}

try:
    response = requests.get('https://api.example.com/protected-data', headers=headers)
    response.raise_for_status()  # 상태 코드가 에러일 경우 예외 발생
except requests.exceptions.HTTPError as err:
    print(f"HTTP error occurred: {err}") 
except Exception as err:
    print(f"An error occurred: {err}")

3. 고급 네트워킹: 멀티스레딩과 비동기 통신

소켓 프로그래밍과 HTTP 클라이언트를 더욱 효율적으로 사용하기 위해 멀티스레딩과 비동기 통신을 활용할 수 있습니다. 이를 통해 여러 클라이언트를 동시에 처리하거나, 네트워크 요청을 비동기적으로 수행할 수 있습니다.

3.1 멀티스레딩을 사용한 소켓 서버

멀티스레딩을 사용하면 여러 클라이언트의 요청을 동시에 처리할 수 있습니다. 아래는 멀티스레딩을 사용한 TCP 서버 예제입니다.

import socket
import threading

def handle_client(client_socket, client_address):
    print(f"{client_address}에서 연결됨.")
    try:
        while True:
            data = client_socket.recv(1024)
            if not data:
                break
            print(f"받은 메시지: {data.decode()}")
            response = f"메시지를 받았습니다 : {data.decode()}".encode()
            client_socket.sendall(response)
    finally:
        client_socket.close()

# 서버 설정
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 65432)
server_socket.bind(server_address)
server_socket.listen(5)
print("서버가 대기 중입니다...")

while True:
    client_socket, client_address = server_socket.accept()
    client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
    client_thread.start()

3.2 비동기 HTTP 요청

비동기 프로그래밍을 사용하면 여러 HTTP 요청을 동시에 처리할 수 있습니다. aiohttp 라이브러리를 사용하여 비동기 HTTP 요청을 구현할 수 있습니다.

import aiohttp
import asyncio

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
        'https://api.example.com/data1',
        'https://api.example.com/data2',
        'https://api.example.com/data3',
    ]
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        results = await asyncio.gather(*tasks)
        for result in results:
            print(result)

asyncio.run(main())

4. 네트워크 보안: SSL/TLS를 사용한 보안 통신

네트워크 통신에서 보안은 매우 중요한 요소입니다. 특히, 데이터를 암호화하지 않고 전송하면 중간에 데이터가 탈취될 위험이 있습니다. 이를 방지하기 위해 SSL/TLS를 사용하여 보안 통신을 구현할 수 있습니다.

4.1 SSL/TLS란?

SSL(Secure Sockets Layer)과 TLS(Transport Layer Security)는 네트워크 통신을 암호화하여 보안을 강화하는 프로토콜입니다. TLS는 SSL의 후속 버전으로, 현재는 주로 TLS가 사용됩니다.

4.2 Python에서 SSL/TLS 사용하기

파이썬에서는 ssl 모듈을 사용하여 SSL/TLS를 적용할 수 있습니다. 아래는 SSL/TLS를 사용한 간단한 TCP 서버와 클라이언트 예제입니다.

SSL/TLS 서버 코드

import socket
import ssl

# SSL 컨텍스트 생성
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile="server.crt", keyfile="server.key")

# 소켓 생성 및 바인딩
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 65432)
server_socket.bind(server_address)
server_socket.listen(1)

# SSL 소켓으로 감싸기
secure_socket = context.wrap_socket(server_socket, server_side=True)
print("SSL 서버가 대기 중입니다...")

while True:
    client_socket, client_address = secure_socket.accept()
    print(f"{client_address}에서 연결됨.")
    try:
        data = client_socket.recv(1024)
        print(f"받은 메시지: {data.decode()}")
        response = f"메시지를 받았습니다 : {data.decode()}".encode()
        client_socket.sendall(response)
    finally:
        client_socket.close()

SSL/TLS 클라이언트 코드

import socket
import ssl

# SSL 컨텍스트 생성
context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
context.load_verify_locations(cafile="server.crt")

# 소켓 생성 및 연결
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
secure_socket = context.wrap_socket(client_socket, server_hostname="localhost")
secure_socket.connect(('localhost', 65432))

try:
    message = "안녕하세요!"
    secure_socket.sendall(message.encode())
    response = secure_socket.recv(1024)
    print(f"서버로부터 받은 응답 : {response.decode()}")
finally:
    secure_socket.close()

5. 네트워크 프로그래밍의 실제 활용 사례

네트워크 프로그래밍은 다양한 실제 애플리케이션에서 활용됩니다. 몇 가지 예를 살펴보겠습니다.

5.1 채팅 애플리케이션

소켓 프로그래밍을 사용하면 실시간 채팅 애플리케이션을 구현할 수 있습니다. 클라이언트와 서버 간의 실시간 통신을 통해 메시지를 주고받는 기능을 구현할 수 있습니다.

예제: 간단한 채팅 서버

import socket
import threading

def handle_client(client_socket, client_address):
    print(f"{client_address}에서 연결됨.")
    try:
        while True:
            data = client_socket.recv(1024)
            if not data:
                break
            print(f"{client_address}: {data.decode()}")
            response = f"서버: {data.decode()}".encode()
            client_socket.sendall(response)
    finally:
        client_socket.close()

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 65432)
server_socket.bind(server_address)
server_socket.listen(5)
print("채팅 서버가 대기 중입니다...")

while True:
    client_socket, client_address = server_socket.accept()
    client_thread = threading.Thread(target=handle_client, args=(client_socket, client_address))
    client_thread.start()

5.2 파일 전송 시스템

소켓 프로그래밍을 통해 파일을 전송하는 시스템을 구축할 수 있습니다. 클라이언트가 서버에 파일을 업로드하거나, 서버에서 파일을 다운로드하는 기능을 구현할 수 있습니다.

예제: 파일 전송 서버

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 65432)
server_socket.bind(server_address)
server_socket.listen(1)
print("파일 전송 서버가 대기 중입니다...")

while True:
    client_socket, client_address = server_socket.accept()
    print(f"{client_address}에서 연결됨.")
    try:
        with open('received_file.txt', 'wb') as file:
            while True:
                data = client_socket.recv(1024)
                if not data:
                    break
                file.write(data)
        print("파일 수신 완료")
    finally:
        client_socket.close()

5.3 웹 스크래핑 및 데이터 수집

HTTP 클라이언트를 사용하여 웹 페이지의 데이터를 스크래핑하거나, API를 통해 데이터를 수집할 수 있습니다. 이는 데이터 분석, 머신 러닝, 비즈니스 인텔리전스 등 다양한 분야에서 활용됩니다.

예제: 웹 페이지 스크래핑

import requests
from bs4 import BeautifulSoup

response = requests.get('https://example.com')
soup = BeautifulSoup(response.text, 'html.parser')
print(soup.title.text)

5.4 IoT(사물인터넷) 통신

IoT 기기 간의 통신을 위해 소켓 프로그래밍이 사용될 수 있습니다. 예를 들어, 센서 데이터를 수집하거나, 원격으로 기기를 제어하는 데 활용할 수 있습니다.

예제: IoT 센서 데이터 수집

import socket

server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 65432)
server_socket.bind(server_address)
server_socket.listen(1)
print("IoT 데이터 수집 서버가 대기 중입니다...")

while True:
    client_socket, client_address = server_socket.accept()
    print(f"{client_address}에서 연결됨.")
    try:
        data = client_socket.recv(1024)
        print(f"수집된 데이터: {data.decode()}")
    finally:
        client_socket.close()

결론

파이썬을 사용하면 소켓 프로그래밍과 HTTP 클라이언트를 통해 다양한 네트워킹 작업을 쉽게 구현할 수 있습니다. 소켓 프로그래밍은 클라이언트-서버 모델을 기반으로 한 통신을 가능하게 하며, HTTP 클라이언트는 웹 서버와의 상호작용을 간편하게 만들어줍니다. 또한, 멀티스레딩과 비동기 프로그래밍을 활용하면 더욱 효율적인 네트워킹 애플리케이션을 개발할 수 있습니다.

728x90