UDP를 이용한 소켓 프로그래밍
UDP 소켓 프로그래밍 과정
- 송신 프로세스가 데이터 패킷을 소켓 밖으로 내기 전에 먼저 패킷에 목적지 주소를 붙여 넣음
- 패킷이 송신자의 소켓을 통과
- 해당 소켓을 인터넷을 통해 수신 프로세스에 있는 소켓으로 라우트함
- 패킷이 수신 소켓에 도착
- 수신 프로세스는 소켓을 통해 해당 패킷을 추출하고 다음에 패킷의 콘텐츠를 조사 및 동작
UDP 패킷 구성
목적지 주소
- 목적지 주소 = 목적지 호스트 IP 주소 + 소켓 포트 번호
목적지 호스트 IP 주소
→ 이를 통해 인터넷의 라우터는 목적지 호스트로 인터넷을 통해 패킷을 라우트 가능소켓 포트 번호
- 포트 번호(port number) : 소켓이 생성될 때 소켓에 할당되는 식별자
- 호스트는 여러 개의 소켓을 갖는 많은 네트워크 애플리케이션 프로세스 수행 가능
→ 소켓 식별이 필요
- 호스트는 여러 개의 소켓을 갖는 많은 네트워크 애플리케이션 프로세스 수행 가능
- 포트 번호(port number) : 소켓이 생성될 때 소켓에 할당되는 식별자
UDP 소켓 프로그래밍 예시
임의의 클라이언트-서버 애플리케이션 사용
- 클라이언트는 키보드로부터 한 줄의 데이터를 읽고 그 데이터를 서버로 보냄
- 서버는 그 데이터를 수신하고 문자를 대문자로 변환
- 서버는 수정된 데이터를 클라이언트에게 보냄
- 클라이언트는 수정된 데이터를 수신하고 그 줄을 화면에 나타냄
UDP 전송 서비스상에서 통신하는 클라이언트-서버의 주요 소켓
- 간단한 애플리케이션 레벨 메시지를 서버에게 보내는 UDP 클라이언트로 시작
- 서버가 클라이언트의 메시지를 수신하고 응답할 수 있도록,
서버는 준비 및 수행되고 있어야 함
→ 즉 클라이언트가 메시지를 전송하기 전에 프로세스를 수행하고 있어야 한다.
프로그램 예시
- 가정
- 클라이언트 프로그램 → UDPClient.py
- 서버 프로그램 → UDPServer.py
- 서버 포트 번호는 12000으로 가정
- 주요 쟁점을 강조하기 위해 최소한의 코드만을 제공
- 오류 같은 것들은 배제
UDPClient.py
from socket import *
serverName = 'hostname'
serverPort = 12000
clientSocket = socket(AF_INET, SOCK_DGRAM)
message = input('Input lowercase sentence:')
clientSocket.sendto(message.encode(),(serverName,serverPort))
modifiedMessage, serverAddress = clientSocket.recvfrom(2048)
print(modifiedMessage.decode())
clientSocket.close()
from socket import *
- socket 모듈을 가져옴 → 프로그램 내에 소켓 생성 가능
serverName = 'hostname'
serverPort = 12000 # 서버 포트 할당
- 호스트 이름은 서버의 IP 주소 혹은 서브의 호스트 이름을 포함하는 문자열을 제공해야 함
- 호스트 이름을 사용하는 경우 IP 주소를 얻기 위해 DNS 검색이 자동으로 수행
clientSocket = socket (AF_INET, SOCK_DGRAM)
- 클라이언트 소켓 할당 <- 클라이언트의 포트 번호를 명시 X
- 운영체제가 클라이언트 포트 번호 명시 작업을 대신해 줌
- 운영체제가 클라이언트 포트 번호 명시 작업을 대신해 줌
AF_INET
: 하부 네트워크가 IPv4를 사용(첫 번째 파라미터 : 주소군(family))SOCK_DGRAM
: UDP 소켓임을 의미
# 메시지 생성
message = input ('Input lowercase sentence:')
- 사용자는 키보드를 이용하여 변수 message에 할당되는 라인을 입력
# 메시지를 소켓을 통해 목적지 호스트로 보냄
clientSocket.sendto(message.encode(),(serverName,serverPort))
encode()
: 문자열 타입의 메시지를 바이트 타입으로 변환sendto()
:- 목적지 주소(serverName, serverPort)를 메시지에 붙이고,
패킷을 프로세스의 클라이언트 소켓에 전송
- 목적지 주소(serverName, serverPort)를 메시지에 붙이고,
- 클라이언트는 패킷을 보낸 후, 서버로부터의 데이터 수신을 기다린다.
modifiedMessage, serverAddress = clientSocket.recvfrom (2048)
- 인터넷에서 클라이언트 소켓으로 패킷이 반환되면 패킷 데이터는 modifiedMessage에 할당
- 동시에 패킷의 출발지 주소는 serverAddress에 할당
- serverAddress는 (서버 IP 주소와 서버 포트 번호 포함)
- serverAddress는 (서버 IP 주소와 서버 포트 번호 포함)
- recvfrom 메서드 또한 2048을 버퍼 크기로 받아들임
print(modifiedMessage.decode())
clientSocket.close() # 소켓을 닫는다. -> 프로세스가 종료됨
- 메시지를 바이트에서 문자열로 변환 후 사용자 화면에 modifiedMessage 출력
UDPServer.py
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
serverSocket.bind(('', serverPort))
print("The server is ready to receive")
while True:
message, clientAddress = serverSocket.recvfrom(2048)
modifiedmessage = message.decode().upper()
serverSocket.sendto(modifiedMessage.encode(),clientAddress)
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_DGRAM)
- UDPClient.py 과정과 동일
- 소켓 모듈 사용, 12000 할당, SOCK_DGRAM 타입 소켓 생성
serverSocket.bind(('', serverPort))
print("The server is ready to receive")
bind
: 포트 번호 12000을 서버의 소켓에 할당한다.
→ UDPServer의 코드는 명시적으로 포트 번호를 소켓에 할당한다.
while True:
- 이제 서버 IP 주소의 12000 포트로 패킷을 보내면 해당 소켓으로 패킷이 전달된다.(directed)
- UDPServer는 계속 패킷을 수신하고 처리할 수 있도록 while 루프로 들어감
→ while 루프를 통해 UDPServer는 패킷이 도착하기를 기다린다.
message, clientAddress = serverSocket.recvfrom(2048)
- 패킷이 서버에 도착하면 패킷의 데이터는 message에 할당
- 패킷의 출발지 주소는 clientAddress에 할당
- clientAddress는 클라이언트 IP 주소와 클라이언트 포트 번호를 포함
- 반송 주소를 제공해야 할 때 이 주소 정보를 사용한다.
- 출발지 주소 정보를 통해 서버는 응답을 어디로 보내야 할지 알 수 있게 됨
modifiedmessage = message.decode().upper()
- 클라이언트로부터의 라인을 받아서 upper()을 이용하여 대문자로 변환
serverSocket.sendto(modifiedMessage.encode(),clientAddress)
- 클라이언트 주소(IP주소와 포트 번호)를 대문자로 변환된 메시지에 붙이고,
그 결과로 만들어진 패킷을 서버의 소켓에 보낸다. - 그 뒤 인터넷 패킷을 클라이언트 주소로 전달한다.
- 서버는 패킷을 보낸 후 while 루프에 머물며 다른 UDP 패킷이 도착하기를 기다린다.