7.1 소켓이란 무엇일까?
좀 더 깊이 파고들어 보자. 처음에는 request
와 작업하는 방법을 배웠고, 그 다음에는 http.client
, 프록시와 함께 작업했어. 다음은? 이제 이 모든 라이브러리의 내부를 들여다볼 차례야...
소켓 (그대로 번역하면 — 콘센트)은 네트워크 상의 한 지점으로, 데이터를 전송하고 수신하는 지점이지. 소켓은 동일하거나 다른 머신에서 실행되는 두 프로그램 간의 양방향 통신 채널의 끝점으로 설명할 수 있어.
소켓은 다양한 네트워크 프로토콜을 지원하지만, 가장 자주 사용되는 것은 두 가지야:
-
TCP
(Transmission Control Protocol): 신뢰할 수 있는 프로토콜로, 연결 설정, 데이터의 무결성 검사 및 올바른 순서를 보장해. -
UDP
(User Datagram Protocol): 연결 지향이 아닌 프로토콜로, 데이터 전송을 보장하지 않지만 특정 유형의 애플리케이션에는 더 빠르고 효율적이야.
소켓을 식별하기 위해서 IP 주소 (네트워크에서 장치를 식별함)와 포트 (장치에서 특정 애플리케이션이나 서비스를 식별함)를 사용해.
중요!
IP 주소와 포트는 네트워크에서 프로그램을 명확히 식별해. 이건 집 주소와 아파트 번호와 같아. 집 주소 (IP 주소)는 네트워크에서 당신의 컴퓨터 주소고, 포트는 프로그램이 메시지를 수신하고 전송하는 데 사용하는 아파트 번호야.
IP 주소와 포트가 무엇인지에 대한 더 자세한 내용은 네트워크 구조에 대한 강의에서 확인할 수 있어.
프로그램의 소켓 작업 기본 단계:
- 소켓 생성: 프로그램은 프로토콜 유형 (TCP 또는 UDP)을 지정하여 소켓을 생성해.
- 주소 연결: 소켓은 연결 가능하거나 데이터를 전송/수신할 수 있도록 IP 주소와 포트 번호에 연결돼.
-
수신 대기 및 연결 설정 (TCP의 경우):
- 수신 대기: 서버 측 소켓은 수신 대기 모드로 전환되고, 들어오는 연결을 기다려.
- 연결 설정: 클라이언트는 서버와의 연결을 시도해. 서버는 연결을 수락하고, 클라이언트와 상호 작용하는 새 소켓을 생성해.
- 데이터 교환: 데이터는 클라이언트와 서버 간에 전송돼. TCP의 경우 데이터는 신뢰할 수 있는 순서로 전송돼.
- 연결 종료: 데이터 교환이 완료된 후 연결이 종료돼.
소켓 사용의 장점:
- 유연성: 소켓은 애플리케이션이 위치 및 플랫폼에 관계없이 데이터를 교환할 수 있도록 해.
- 성능: 소켓은 특히 UDP를 사용하여 데이터를 빠르고 효율적으로 전송하는 방법을 제공해.
- 신뢰성 (TCP의 경우): TCP 프로토콜은 데이터의 무결성 검사 및 손실된 패킷 복구와 함께 신뢰할 수 있는 데이터 전송을 보장해.
7.2 소켓 서버 만들기
파이썬에서 소켓 작업은 저수준 네트워크 프로그래밍 인터페이스를 제공하는 내장 모듈 socket
로 수행돼.
소켓을 사용하여 socket 서버
를 만들 수 있어 — 이는 클라이언트로부터 요청을 받고 응답하는 애플리케이션/객체야. 또한 socket 클라이언트
— 이는 socket 서버
에 요청을 보내고 응답을 받는 애플리케이션/객체야.
socket 서버
를 생성하려면 세 가지 작업을 수행해야 해:
- socket 서버 객체를 생성해.
- 어떤 IP와 포트에
bind
(연결) 해. - 들어오는 메시지를
listen
(수신 대기) 모드로 설정해.
이 코드는 대략 이렇게 보일 거야:
import socket
# 소켓 생성
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 소켓을 주소 및 포트에 연결
server_socket.bind(('localhost', 12345))
# 들어오는 연결을 수신 대기
server_socket.listen(5)
print("서버가 연결을 기다리고 있어...")
여기서 socket.AF_INET
은 네트워크 프로토콜에 IPv4를 사용한다고 지정하고, socket.SOCK_STREAM
은 TCP를 사용한다고 설정해. 이 매개변수는 네트워크 애플리케이션을 만드는 데 가장 자주 사용돼.
들어오는 메시지가 들어오면 네 가지 작업을 더 수행해야 해:
- 클라이언트와
(accept)
연결을 설정해. - 클라이언트로부터 요청(데이터)을
(receive)
받아. - 클라이언트에게 어떤 데이터로 응답을
(send)
해. - 연결을
(close)
해.
이 코드는 대략 이렇게 보일 거야:
# 새로운 연결 수락
client_socket, client_address = server_socket.accept()
print(f"연결이 {client_address}와(과) 설정되었어")
# 클라이언트로부터 데이터 받기
data = client_socket.recv(1024)
print(f"수신됨: {data.decode('utf-8')}")
# 클라이언트에게 데이터 보내기
client_socket.sendall(b'Hello, client!')
# 클라이언트와의 연결 종료
client_socket.close()
sendall()
메서드는 send()
메서드 대신 사용돼, 왜냐하면 모든 데이터가 전송되도록 보장하거든. send()
메서드는 버퍼가 가득 차면 데이터의 일부만 전송할 수 있어.
recv(1024)
에서 1024는 한 번에 받을 수 있는 최대 바이트 수를 지정해. 이는 한 번에 처리되는 데이터 양을 제어하는 데 도움을 줘.
마지막 예제의 코드는 일반적으로 무한 루프 내에서 실행돼 — 서버는 요청을 처리하고, 그 다음 새로운 요청을 기다리고, 그걸 처리하고, 계속 반복해.
이 코드를 자신이 실행하거나 전체 예제를 보고 싶다면, 여기서 가져왔어:
import socket
# 소켓 생성
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 소켓을 주소 및 포트에 연결
server_socket.bind(('localhost', 12345))
# 들어오는 연결을 수신 대기
server_socket.listen(5)
print("서버가 연결을 기다리고 있어...")
while True:
# 새로운 연결 수락
client_socket, client_address = server_socket.accept()
print(f"연결이 {client_address}와(과) 설정되었어")
# 클라이언트로부터 데이터 받기
data = client_socket.recv(1024)
print(f"수신됨: {data.decode('utf-8')}")
# 클라이언트에게 데이터 보내기
client_socket.sendall(b'Hello, client!')
# 클라이언트와의 연결 종료
client_socket.close()
7.3 소켓 클라이언트 만들기
소켓 서버를 만들었으니, 이제 서버에 요청을 보내고 응답을 받을 소켓 클라이언트를 작성해 보자.
이 작업을 위해서는 다섯 가지 작업을 수행해야해:
socket 클라이언트
객체를 생성해.- 우리의
socket 서버
의 IP 주소 및 포트와(connect)
연결을 설정해. - 서버에 메시지를
(send)
보내. - 서버로부터 데이터를
(receive)
받아. - 연결을
(close)
해.
사실 이건 생각보다 간단해. 이 코드는 대략 이렇게 보일 거야:
import socket
# 소켓 생성
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 서버와의 연결 설정
client_socket.connect(('localhost', 12345))
# 서버에 데이터 보내기
client_socket.sendall(b'Hello, server!')
# 서버로부터 데이터 받기
data = client_socket.recv(1024)
print(f"서버로부터 수신됨: {data.decode('utf-8')}")
# 소켓 종료
client_socket.close()
만약 그쪽에 socket 서버
가 실행 중이 아니거나 연결이 끊어지면 socket.error
유형의 예외가 발생해. 그러니 예외 처리를 잊지 마.
이것으로 우리는 오늘 소켓 작업을 마무리할게.
네트워크 작업을 할 때마다 호스트, 포트, IP 주소, 연결 설정, 요청 수신 등이 반복적으로 나타날 거야. 그러니 이게 내부 깊숙이 어떻게 작동하는지 이해하는 것은 당신의 삶을 크게 바꾸어 주고 흩어져 있는 지식을 하나의 그림으로 통합하는 데 큰 도움이 될 거야.
GO TO FULL VERSION