본문 바로가기
프로그래밍/Network

[Network]네트워크를 내 손안에: 소켓 프로그래밍 입문! 💻

by 다다면체 2025. 1. 11.
728x90
반응형
반응형

인터넷이 어떻게 돌아가는지, 우리가 쓰는 앱들이 어떻게 데이터를 주고받는지 궁금했던 적 있으신가요? 그 비밀은 바로 "소켓 프로그래밍"에 숨어있답니다! 마치 두 건물이 전화선으로 연결되어 서로 통화하는 것처럼, 소켓은 컴퓨터들이 네트워크를 통해 데이터를 주고받을 수 있게 해주는 통로 역할을 해요. 오늘은 이 소켓 프로그래밍의 기본부터 간단한 예제, 그리고 조금 더 심화된 내용까지 함께 쉽고 재미있게 알아볼 거예요!

 


1. 소켓이란 무엇일까? 🧩

 

소켓(Socket)은 네트워크에서 데이터를 주고받기 위한 "연결 지점"이라고 생각하면 쉬워요. 마치 집집마다 있는 우편함처럼, 데이터를 보내는 곳과 받는 곳의 주소가 명확해야 정확하게 전달할 수 있겠죠? 소켓도 IP 주소와 포트 번호라는 주소를 가지고 있어서, 데이터를 정확하게 목적지까지 전달해 준답니다.

🔹 소켓의 주요 기능:

  • 통신 채널 생성: 소켓은 데이터를 주고받기 위한 통로, 즉 "채널"을 만들어 줘요.
  • 다양한 통신 방식 지원 (프로토콜): TCP, UDP처럼 데이터를 주고받는 다양한 "방식"을 지원해요. 마치 택배, 등기, 우편처럼 각기 다른 배송 방식이 있는 것과 같아요.
  • 양방향 소통: 데이터를 보내기도 하고 받기도 하는, 양방향 통신이 가능해요. 마치 전화 통화처럼요!

비유: 소켓은 마치 편지를 주고받기 위한 우체통과 같아요. 정확한 주소(IP와 포트)가 있어야 편지를 제대로 전달할 수 있듯이, 소켓도 정확한 주소를 가지고 있어야 데이터를 정확하게 주고받을 수 있답니다.📬


2. 소켓 프로그래밍의 작동 원리 🌐

 

소켓 프로그래밍은 보통 "클라이언트-서버" 모델로 작동해요. 마치 식당에 손님(클라이언트)이 찾아가서 음식을 주문하고, 식당(서버)이 음식을 제공하는 것과 같은 원리죠.

🔹 클라이언트-서버 통신 흐름:

  • 서버의 역할:
    1. 소켓 생성: 식당 문을 여는 것과 같아요.
    2. 주소 설정 (바인딩): 식당 주소를 정하는 것과 같아요.
    3. 손님 기다리기 (리스닝): 손님이 오기를 기다리는 것과 같아요.
    4. 손님 맞이하기 (억셉트): 손님이 들어오면 맞이하는 것과 같아요.
    5. 주문받고 음식 주기 (데이터 송수신): 손님의 주문을 받고 음식을 제공하는 것과 같아요.
  • 클라이언트의 역할:
    1. 소켓 생성: 식당에 가기 위해 택시를 잡는 것과 같아요.
    2. 식당 주소로 이동 (연결 요청): 식당 주소로 택시를 타고 가는 것과 같아요.
    3. 주문하고 음식 받기 (데이터 송수신): 음식을 주문하고 받는 것과 같아요.

3. 어떤 방식으로 통신할까요? (TCP와 UDP)📜

소켓 프로그래밍에서는 데이터를 어떻게 주고받을지 정하는 "통신 방식"이 있어요. 대표적인 두 가지 방식이 바로 TCP와 UDP랍니다.

🔹 TCP와 UDP 비교:

연결 방식 연결 후 통신 (전화 통화 후 대화) 연결 없이 바로 전송 (메시지 던지기)
신뢰성 데이터 전달 보장 (분실 시 재전송 요청) 데이터 전달 보장 안 함 (빠른 속도 우선)
속도 상대적으로 느림 (확인 절차 때문에) 상대적으로 빠름 (확인 절차 없음)
사용 사례 파일 전송, 이메일, 웹 브라우징 (정확한 전달 중요) 실시간 스트리밍, 온라인 게임 (빠른 속도 중요)
  • TCP (Transmission Control Protocol): 마치 "택배"와 같아요. 보내는 사람이 물건을 포장하고, 받는 사람에게 안전하게 전달될 때까지 확인하는 꼼꼼한 방식이죠. 데이터가 순서대로 정확하게 전달되는 것이 중요할 때 사용합니다.
  • UDP (User Datagram Protocol): 마치 "퀵 서비스"와 같아요. 물건을 빠르게 전달하는 것이 목적이기 때문에, 포장이나 도착 확인 같은 절차를 생략하는 방식이죠. 속도가 중요하고, 약간의 데이터 손실은 감수할 수 있을 때 사용합니다.

주요 소켓 함수들:

  • socket(): 소켓을 만드는 함수 (우체통 만들기)
  • bind(): 소켓에 주소(IP와 포트)를 할당하는 함수 (우체통 주소 정하기)
  • listen(): 클라이언트의 연결 요청을 기다리는 함수 (서버만 사용, 손님 기다리기)
  • accept(): 클라이언트의 연결 요청을 수락하는 함수 (서버만 사용, 손님 맞이하기)
  • connect(): 서버에 연결을 요청하는 함수 (클라이언트만 사용, 식당 찾아가기)
  • send()/recv(): 데이터를 보내고 받는 함수 (편지 주고받기)
  • close(): 소켓을 닫는 함수 (통신 종료, 우체통 닫기)

4. 간단한 소켓 프로그래밍 예제 🖥️

간단한 파이썬 코드를 통해 TCP 통신이 어떻게 이루어지는지 살펴볼까요?

(1) TCP 서버 (server.py):

import socket

# 서버 소켓 생성 (우체통 만들기)
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 주소 할당 (우체통 주소 정하기)
server_socket.bind(('127.0.0.1', 12345)) # 127.0.0.1은 자기 컴퓨터 주소, 12345는 포트 번호
# 연결 대기 (손님 기다리기)
server_socket.listen(1)
print('서버가 손님을 기다리고 있습니다...')

# 손님 맞이하기 (손님과 통신할 새로운 소켓 생성)
conn, addr = server_socket.accept()
print(f'손님이 접속했습니다! 주소: {addr}')

# 데이터 주고받기 (주문받고 음식 주기)
while True:
    data = conn.recv(1024) # 손님의 주문 받기
    if not data: # 손님이 나가면 종료
        break
    print(f'손님이 주문한 내용: {data.decode()}')
    conn.sendall(data)  # 받은 내용을 그대로 돌려주는 에코 서버

# 연결 종료 (통신 종료)
conn.close()
server_socket.close()

 

(2) TCP 클라이언트 (client.py):

import socket

# 클라이언트 소켓 생성 (택시 잡기)
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 서버에 연결 요청 (식당 찾아가기)
client_socket.connect(('127.0.0.1', 12345))

# 데이터 보내기 (주문하기)
client_socket.sendall(b'Hello, Server! I would like some pizza!')
# 데이터 받기 (음식 받기)
data = client_socket.recv(1024)
print(f'서버가 보내온 답장: {data.decode()}')

# 연결 종료 (식당에서 나오기)
client_socket.close()

이 코드를 실행해보면, 클라이언트에서 보낸 메시지가 서버에 전달되고, 서버는 받은 메시지를 그대로 다시 클라이언트에게 보내주는 것을 확인할 수 있습니다.


5. 소켓 옵션과 고급 설정 🔧

🔹 주요 소켓 옵션:

  • SO_REUSEADDR: 이미 사용 중인 포트를 재사용할 수 있도록 설정
  • SO_KEEPALIVE: 연결 유지 여부 확인
  • SO_RCVBUF / SO_SNDBUF: 송수신 버퍼 크기 조정

 

  • 소켓 옵션: 소켓의 동작 방식을 더 세밀하게 조절할 수 있는 설정들이 있어요. 예를 들어, SO_REUSEADDR 옵션을 사용하면 이미 사용 중인 포트를 다시 사용할 수 있게 해주고, SO_KEEPALIVE 옵션을 사용하면 연결이 끊어졌는지 주기적으로 확인할 수 있어요.

🔹 비동기 소켓 프로그래밍:

  • select() / poll(): 여러 소켓의 상태를 동시에 감시
  • asyncio: Python에서 비동기 네트워크 프로그래밍을 위한 라이브러리
  • 비동기 소켓 프로그래밍: 여러 개의 소켓을 동시에 관리해야 할 때 유용한 방법이에요. 마치 여러 명의 손님을 동시에 응대해야 하는 식당과 같아요. select()나 poll() 같은 함수를 사용하거나, 파이썬의 asyncio 라이브러리를 활용하면 비동기적으로 네트워크 프로그래밍을 할 수 있습니다.

 


6. 실습: UDP 기반 채팅 애플리케이션 🗣️

 

이번에는 조금 더 재미있는 예제를 만들어 볼까요? 바로 UDP를 이용한 간단한 채팅 애플리케이션입니다! UDP는 속도가 빠르기 때문에 실시간으로 메시지를 주고받는 채팅에 적합하답니다.

 

(1) UDP 서버 (udp_server.py):

import socket

# UDP 소켓 생성
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 주소 할당
server_socket.bind(('127.0.0.1', 12345))
print('UDP 채팅 서버가 시작되었습니다. 메시지를 기다립니다...')

while True:
    # 메시지 받기 (보낸 사람의 주소도 함께 받음)
    data, addr = server_socket.recvfrom(1024)
    print(f'{addr}로부터 메시지: {data.decode()}')
    # 받은 메시지를 다시 보낸 사람에게 전달 (에코)
    server_socket.sendto(data, addr)

 

(2) UDP 클라이언트 (udp_client.py):

import socket

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

while True:
    message = input('메시지를 입력하세요 (종료: q): ')
    if message.lower() == 'q':
        break
    # 메시지 보내기 (서버 주소와 함께)
    client_socket.sendto(message.encode(), ('127.0.0.1', 12345))
    # 서버로부터 응답 받기
    data, _ = client_socket.recvfrom(1024) # _는 서버 주소를 무시하기 위해 사용
    print(f'서버로부터 받은 답장: {data.decode()}')

client_socket.close()

 

이 코드를 실행하면, 여러 클라이언트가 동시에 서버에 메시지를 보내고 받을 수 있는 간단한 채팅 프로그램을 만들 수 있습니다. TCP와는 달리 연결 설정 없이 메시지를 바로 보내는 방식을 확인할 수 있습니다.


7. 소켓 프로그래밍, 어디에 쓰일까요?📌

  • 웹 서버 및 브라우저: 웹 페이지를 보여주는 웹 서버와 우리가 사용하는 웹 브라우저는 모두 소켓을 사용하여 통신합니다.
  • 온라인 게임: 실시간으로 데이터를 주고받아야 하는 온라인 게임에서도 소켓 프로그래밍이 핵심적인 역할을 합니다.
  • 메신저 애플리케이션: 카카오톡, 텔레그램과 같은 메신저 앱들도 소켓을 사용하여 메시지를 주고받습니다.
  • 파일 공유 프로그램: 토렌트와 같은 P2P 파일 공유 프로그램도 소켓을 사용하여 파일을 주고받습니다.
  • IoT (Internet of Things): 사물 인터넷 기기들이 데이터를 주고받을 때도 소켓을 사용합니다.

8. 마치며 ✨

소켓 프로그래밍은 네트워크 통신의 기본 원리를 이해하고, 다양한 네트워크 애플리케이션을 만들 수 있도록 해주는 중요한 기술입니다. 마치 건물을 짓기 위한 기초 공사와 같은 역할을 하죠. 이 글을 통해 소켓 프로그래밍의 기본 개념과 활용 방법을 쉽게 이해하셨기를 바랍니다. 이제 여러분도 네트워크 프로그래밍의 세계를 탐험할 준비가 되셨나요? 궁금한 점이 있다면 언제든지 질문해주세요!

 

728x90
반응형