프로그래밍/Python

네트워킹 기초: Python 소켓 프로그래밍 완벽 가이드

shimdh 2025. 2. 28. 09:16
728x90

네트워크 소켓 프로그래밍은 컴퓨터 간의 데이터 통신을 가능하게 하는 핵심 기술입니다. 인터넷 기반의 애플리케이션, 서버-클라이언트 시스템, 실시간 데이터 전송 등의 기능을 구현할 때 소켓(Socket) 을 활용하면 안정적인 네트워크 통신이 가능합니다.

Python에서는 socket 모듈을 사용하여 간단한 소켓 프로그래밍을 수행할 수 있으며, 이를 통해 TCP/IP 기반의 통신을 구현할 수 있습니다. 이번 글에서는 소켓의 개념, 클라이언트-서버 모델, TCP 및 UDP 소켓 구현 방법, 실전 예제 및 최적화 기법까지 자세히 다뤄보겠습니다.


1. 소켓(Socket) 개념 및 기본 원리

🔹 소켓이란?

소켓(Socket)네트워크를 통해 두 개의 프로그램이 데이터를 송수신할 수 있도록 하는 통신 인터페이스입니다. 소켓을 이용하면 컴퓨터 간, 프로세스 간 데이터를 교환할 수 있으며, 원격 서버와 클라이언트 간의 연결을 설정할 수 있습니다.

소켓은 IP 주소와 포트 번호를 기반으로 작동하며, 이를 통해 서로 다른 시스템 간 통신이 가능합니다.

🔹 주요 개념 정리

  1. 소켓(Socket): 네트워크에서 데이터 송수신을 위한 논리적 연결 지점.
  2. 클라이언트(Client): 데이터를 요청하는 역할. (예: 웹 브라우저)
  3. 서버(Server): 클라이언트의 요청을 처리하고 응답을 보내는 역할. (예: 웹 서버)
  4. 포트(Port): 네트워크에서 특정 애플리케이션을 구분하는 식별 번호. (예: HTTP - 80, HTTPS - 443)
  5. TCP(Transmission Control Protocol): 신뢰성 있는 연결 기반 통신을 지원하는 프로토콜.
  6. UDP(User Datagram Protocol): 빠른 데이터 전송이 필요한 비연결형 프로토콜.

2. 소켓 프로그래밍의 흐름

소켓 프로그래밍의 기본적인 과정은 다음과 같습니다.

  1. 소켓 생성: socket.socket()을 이용해 소켓 객체를 생성.
  2. 주소 바인딩: 서버 측에서 특정 IP 주소와 포트를 지정(bind()).
  3. 연결 대기(서버): 서버가 클라이언트의 요청을 수락할 준비(listen()).
  4. 연결 요청(클라이언트): 클라이언트가 서버에 연결 요청(connect()).
  5. 데이터 송수신: send()recv() 메서드를 통해 데이터를 주고받음.
  6. 연결 종료: 사용이 끝나면 close()를 호출하여 소켓 종료.

3. TCP 기반 소켓 프로그래밍 (클라이언트-서버 모델)

TCP(Transmission Control Protocol)는 신뢰성이 보장되는 연결 지향형 프로토콜입니다. 데이터 전송이 순서대로 이루어지며, 패킷 손실 시 재전송이 이루어집니다.

🔹 TCP 서버 구현

import socket

# 1. 소켓 생성 (IPv4, TCP)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 2. 주소 바인딩 (IP, 포트 설정)
server_socket.bind(('localhost', 65432))

# 3. 연결 대기 (최대 1개 클라이언트 대기)
server_socket.listen(1)
print("서버 대기 중...")

while True:
    # 4. 클라이언트 연결 수락
    client_socket, client_address = server_socket.accept()
    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:
        # 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())

    # 4. 응답 수신
    response = client_socket.recv(1024)
    print(f"서버 응답: {response.decode()}")

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

✅ 실행 흐름

  1. 서버가 실행되면 포트 65432에서 클라이언트의 요청을 기다림.
  2. 클라이언트가 서버에 연결하고 "안녕하세요!" 메시지를 보냄.
  3. 서버가 메시지를 받고 "서버 응답: 안녕하세요!" 를 반환.
  4. 클라이언트가 응답을 출력하고 종료.

4. UDP 기반 소켓 프로그래밍 (빠른 데이터 전송)

UDP(User Datagram Protocol)는 TCP와 달리 연결 과정이 필요 없는 비연결형 프로토콜입니다. 데이터가 빠르게 전송되지만, 패킷 손실이 발생할 수 있습니다.

🔹 UDP 서버 구현

import socket

# 1. UDP 소켓 생성
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

# 2. 주소 바인딩
server_socket.bind(('localhost', 65432))

print("UDP 서버 대기 중...")

while True:
    data, client_address = server_socket.recvfrom(1024)
    print(f"{client_address}에서 받은 메시지: {data.decode()}")

    response = f"서버 응답: {data.decode()}".encode()
    server_socket.sendto(response, client_address)

🔹 UDP 클라이언트 구현

import socket

# 1. UDP 소켓 생성
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

server_address = ('localhost', 65432)

try:
    # 2. 데이터 전송
    message = "UDP 메시지 전송"
    client_socket.sendto(message.encode(), server_address)

    # 3. 응답 수신
    response, _ = client_socket.recvfrom(1024)
    print(f"서버 응답: {response.decode()}")

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

✅ 실행 흐름

  1. UDP 서버는 포트 65432에서 데이터를 기다림.
  2. 클라이언트가 "UDP 메시지 전송" 메시지를 서버로 보냄.
  3. 서버가 메시지를 받아 "서버 응답: UDP 메시지 전송"을 클라이언트로 응답.
  4. 클라이언트가 메시지를 출력하고 종료.

5. 소켓 프로그래밍 최적화 팁

✅ 다중 클라이언트 처리 (멀티스레딩)

  • 기본 TCP 서버는 한 번에 하나의 클라이언트만 처리하지만, 멀티스레딩(Threading) 을 사용하면 여러 클라이언트를 동시에 처리할 수 있음.
  • threading 또는 asyncio를 활용하여 동시 접속 지원 가능.
import threading

def handle_client(client_socket):
    while True:
        data = client_socket.recv(1024)
        if not data:
            break
        client_socket.sendall(data)
    client_socket.close()

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

✅ 비동기 네트워크 프로그래밍 (asyncio 활용)

  • asyncio를 사용하면 비동기 네트워크 프로그래밍이 가능하여 고성능 서버 구현이 가능.

🔥 결론: Python 소켓 프로그래밍으로 강력한 네트워크 애플리케이션 개발

소켓 프로그래밍을 이해하면 웹 애플리케이션, 네트워크 기반 게임, 실시간 메시징 시스템, IoT 통신 등 다양한 분야에서 활용할 수 있습니다.

🎯 핵심 정리

  • 소켓은 네트워크를 통한 데이터 송수신을 위한 인터페이스.
  • TCP는 신뢰성이 높은 연결형 통신, UDP는 빠른 비연결형 통신.
  • 멀티스레딩 및 비동기 프로그래밍을 활용하면 확장성이 뛰어난 서버를 구현 가능.

Python의 소켓 프로그래밍을 익히고, 실제 프로젝트에서 효율적인 네트워크 애플리케이션을 개발해 보세요! 🚀

728x90