본문 바로가기

Computer Science/Computer Network

TCP & UDP 통신 실습: 동일 PC

TCP 통신

< Server Code >

# -*- coding: utf-8 -*-

from socket import *

# 서버의 IP와 포트번호
serverName = '192.168.0.133'
serverPort = 15000

# 서버 소켓 생성
serverSocket = socket(AF_INET, SOCK_STREAM) # AF_INET: IPv4주소 체계 사용,  SOCKET_STREAM: TCP 소켓 생성

# Socket Binding: 서버 소켓에 IP주소와 포트 번호 할당
serverSocket.bind((serverName, serverPort)) 

# 서버 소켓을 통해 클라이언트의 연결 요청 대기
serverSocket.listen(1) # 1: 최대 1개의 연결 요청만 저장 가능 (1개의 클라이언트만 서버에 연결 가능)

print("The server is ready to receive")

# 무한루프를 통해 클라이언트의 연결 요청 대기
while 1:
    # 연결 요청 수락 -> 클라이언트 소켓과 주소 반환
    clientSocket, addr = serverSocket.accept()
    print(f"connected with {addr}.")
    
    # 연결된 클라이언트로부터 데이터 수신 (바이트 문자열로 수신 != 유니코드 문자열)
    sentence = clientSocket.recv(2048) # 최대 2048 Byte 데이터 수신 가능
    
    # 받은 문자 데이터를 대문자로 변환
    capitalizedSentence = sentence.upper()
    
    # 변환한 데이터를 다시 클라이언트에게 전송
    clientSocket.send(capitalizedSentence)
    print(f"{capitalizedSentence} were sent to client.")
    
    # 연결된 클라이언트 소켓 닫기 (서버 소켓은 계속 열려 있음)    
    clientSocket.close()
    
    # 변환 데이터가 "ENDS"라면 서버 소켓 닫기 (루프 종료)
    if capitalizedSentence == b'ENDS': # b: 바이트 문자열로 비교
        serverSocket.close()
        break

 

< Client Code >

# -*- coding: utf-8 -*-

from socket import *

# 클라이언트가 접속할 서버의 IP주소와 포트번호
serverName = '192.168.0.133'
serverPort = 15000

# 클라이언트 소켓 생성
clientSocket = socket(AF_INET, SOCK_STREAM) # AF_INET: IPv4주소 체계 사용,  SOCKET_STREAM: TCP 소켓 생성

# 접속할 서버에 연결 요청
clientSocket.connect((serverName, serverPort))

# 서버에 전송할 데이터 입력
sentence = input("Input lowercase sentence: ")

# (바이트 문자열로 인코딩 후) 서버에게 데이터 전송 
clientSocket.send(sentence.encode())

# 서버로부터 수정된 메세지 수신 
modifiedSentence = clientSocket.recv(2048)
print("From Server: ", modifiedSentence)

# 통신 완료 -> 클라이언트 소켓 닫기
clientSocket.close()

 

< 결과 >


UDP 통신

< Server Code >

# -*- coding: utf-8 -*-

from socket import *

# 서버의 IP와 포트번호
serverName = '192.168.0.133'
serverPort = 15000
ADDR = (serverName, serverPort)

# 서버 소켓 생성
serverSocket = socket(AF_INET, SOCK_DGRAM) # AF_INET: IPv4주소 체계 사용,  SOCKET_DGRAM: UDP 소켓 생성

# Socket Binding: 서버 소켓에 IP주소와 포트 번호 할당
serverSocket.bind(ADDR)

print("The server is ready to receive")

# 무한루프를 통해 클라이언트의 연결 요청 대기
while 1:
    # 아무 클라이언트로부터 데이터 수신 (특정 클라이언트 x)
    sentence, addr = serverSocket.recvfrom(2048) # 최대 2048 Byte 데이터 수신 가능
    
    # 받은 문자 데이터를 대문자로 변환
    capitalizedSentence = sentence.upper()
    
    # 변환한 데이터를 다시 클라이언트에게 전송
    serverSocket.sendto(capitalizedSentence, addr)
    print(f"{capitalizedSentence} were sent to client.")

    # 변환 데이터가 "ENDS"라면 서버 소켓 닫기 (루프 종료)
    if capitalizedSentence == b'ENDS': # b: 바이트 문자열로 비교
        serverSocket.close()
        break

 

< Client Code >

# -*- coding: utf-8 -*-

from socket import *

# 서버의 IP와 포트번호
serverName = '192.168.0.133'
serverPort = 15000
ADDR = (serverName, serverPort)

# 서버 소켓 생성
serverSocket = socket(AF_INET, SOCK_DGRAM) # AF_INET: IPv4주소 체계 사용,  SOCKET_DGRAM: UDP 소켓 생성

# Socket Binding: 서버 소켓에 IP주소와 포트 번호 할당
serverSocket.bind(ADDR)

print("The server is ready to receive")

# 무한루프를 통해 클라이언트의 연결 요청 대기
while 1:
    # 아무 클라이언트로부터 데이터 수신 (특정 클라이언트 x)
    sentence, addr = serverSocket.recvfrom(2048) # 최대 2048 Byte 데이터 수신 가능
    
    # 받은 문자 데이터를 대문자로 변환
    capitalizedSentence = sentence.upper()
    
    # 변환한 데이터를 다시 클라이언트에게 전송
    serverSocket.sendto(capitalizedSentence, addr)
    print(f"{capitalizedSentence} were sent to client.")

    # 변환 데이터가 "ENDS"라면 서버 소켓 닫기 (루프 종료)
    if capitalizedSentence == b'ENDS': # b: 바이트 문자열로 비교
        serverSocket.close()
        break

 

< 결과 >


와이어샤크 캡쳐 및 분석

그냥 동일한 PC에서 Server/Client 실행 시 캡쳐가 되지 않는다.

 

왜 일까?

 

바로 루프백 인터페이스때문이다.

 

루프백 인터페이스란 동일한 컴퓨터 내에서 통신을 할 때 사용되는 가상의 인터페이스(전송 통로)이다.

 

일반적으로 이더넷 인터페이스로 데이터를 보내면 게이트웨이인 라우터에 도달하지만, 루프백 인터페이스로 데이터를 보내면 자신의 컴퓨터로 돌아온다.

 

와이어샤크는 네트워크 분석의 효율성을 높이기 위해 기본적으로 루프백 인터페이스에서의 트래픽을 캡쳐하지 않는다.

 

하지만, 캡쳐할 네트워크 인터페이스를 루프백 인터페이스로 설정하면 가능하다.

캡쳐 -> 옵션 -> Adapter for loopback traffic capture 를 선택하면 된다.

 

<  TCP 루프백 인터페이스 캡쳐 결과 >

 

<  UDP 루프백 인터페이스 캡쳐 결과 >