네트워크 프로그래밍 - Socket, Echo server와 Echo client (Python)

728x90
반응형

출처 : https://www.youtube.com/watch?v=GScMb0YDr70&list=PLw-ln7ZaFg2FXc10cyVhAcn2W1foBzwN5&index=3

 

개요

 

이번에는 파이썬을 통해 socket과 echo client, echo server를 구현하여 네트워크 통신의 기본적인 원리를 이해해보도록 한다.

 

소켓(Socket) : 컴퓨터 간의 데이터 전송을 위한 인터페이스

 

에코 서버(Echo Server) : 클라이언트가 전송하는 데이터를 그대로 되돌려 전송해 주는 기능의 서버. 즉, 클라이언트가 보낸 데이터를 수신해서 동일한 데이터를 다시 클라이언트에게 송신한다.

 

에코 클라이언트(Echo Client) : 에코 서버에 접속하여 데이터를 전송하고, 서버로부터 전송 받은 데이터를 출력한다.

 

# socket 객체 생성

import socket

server = socket.socket()

 

파이썬에서 소켓 모듈을 가져오는 방법은 매우 간단하다. import socket을 작성해주기만 하면 된다.

 

socket 객체는 socket 모듈안의 socket 클래스를 통해 생성할 수 있다. (server = socket.socket())

socket 클래스는 4개의 인자(argument)를 받는데, 2개만 줘도 socket 객체가 만들어진다. 만약아무것도 입력을 안해주면 기본값으로 설정된다.

 

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

 

여기서 socket.AF_INET은 IPv4를 사용하는 소켓을 생성할 때 사용되는 상수이다. 만약 IPv6를 사용하고 싶다면 socket.AF_INET6를 사용하면 된다.

 

socket.SOCK_STREAM은 소켓의 타입을 지정해주는 상수이다.

socket.SOCK_STREAM은 TCP 소켓을 생성해서, 데이터 전송 순서를 유지하며, 전송 중 오류가 발생하면 재전송을 요청한다.

socket.SOCK_DGRAM은 UDP 소켓을 생성해서, 데이터 전송 순서를 유지하지 않으며, 전송 중 오류가 발생해도 재전송을 요청하지 않는다.

 

IP와 TCP, UDP의 자세한 설명은 이전에 올려둔 네트워크 강좌를 참고해보는 것을 추천한다.

 

 

# Echo Server

#echo server
import socket

server = socket.socket()
host = '127.0.0.1'
port = 6543

server.bind((host, port))
server.listen()

conn, addr = server.accept()
data = conn.recv(1024)
conn.send(data)

 

에코 서버의 파이썬 코드는 위와 같다.

 

먼저 server 라는 소켓 객체를 생성하고 host의 IP address와 port 를 정해준다. 우리는 실습만 하기 때문에 루프백 IP 주소와 비어있는 port 번호를 사용한다.

 

server.bind(=socket.socket().bind())에서 bind는 소켓을 특정 IP 주소와 포트 번호에 연결하는 것이다. 즉 bind() 함수를 통해 해당 IP 주소와 포트 번호로 들어오는 데이터를 수신할 수 있게 만들어준다. 우리는 루프백 IP 주소를 사용했으므로 자기 자신만 수신할 수 있다. 만약 모든 사람의 데이터를 수신할 수 있게 만들어주고 싶으면 0.0.0.0 으로 설정해주면 된다.

 

server.listen(socket.socket().listen())은 소켓 객채를 리스닝 상태로 만든다. 즉, 지정된 포트에서 들어오는 연결 요청을 대기하게 된다.

 

accept() 함수는 클라이언트의 연결 요청을 받아들이고, 클라이언트와 연결된 소켓 객체와 클라이언트의 IP주소와 포트 번호를 반환한다. 여기서 conn이 반환된 소켓 객체고, addr이 클라이언트의 IP 주소와 포트 번호다.

 

recv()는 클라이언트에게서 데이터를 받기 위해 사용하는 함수이다. 1024는 1024 바이트만큼 받겠다라는 의미이다.

 

send()는 클라이언트에게 데이터를 전송하는 함수이다. send(data)를 함으로써 클라이언트에게 받은 데이터를 다시 그대로 보내게 된다.

 

 

# Echo Client

# echo_client
import socket

client = socket.socket()
host = '127.0.0.1'
port = 6543
client.connect((host, port))
client.send("헬로 월드".encode('utf-8'))
print(client.recv(1024).decode('utf-8'))

 

에코 클라이언트의 파이썬 코드는 위와 같다.

 

Client라는 socket 객체를 생성한다.

 

connect() 함수를 사용해 서버에 액세스한다. 인자를 정해줘야 하는데 host(어디에 접속할지), port(어떤 포트로 접속할지)를 정해줘야 한다.

 

send() 함수를 사용해 서버에게 전송할 데이터를 보낸다. 우리는 문자형 데이터를 보낼 것이기 때문에 encode('utf-8')을 사용한다. 영어 메시지를 보낼 때에는 뒤에 decode는 안붙여도 된다. 하지만 한글 메시지를 보낼 때는 붙여서 보내줘야 한다.

 

 

실행할 때에는 에코 서버를 먼저 실행한 다음 에코 클라이언트를 실행해주면 된다.

 

실습

여러 메시지를 보내고 싶을 때는 그럼 어떻게 해야할까?

 

# 에코 서버 코드

#echo server
import socket

server = socket.socket()
host = '127.0.0.1'
port = 6543

server.bind((host, port))
server.listen()

conn, addr = server.accept()
while True:
    data = conn.recv(1024)
    if not data:
        break
    conn.send(data)
conn.close()

 

# 에코 클라이언트 코드

# echo_client
import socket

client = socket.socket()
host = '127.0.0.1'
port = 6543
client.connect((host, port))

for i in range(32):
    client.send("헬로 월드".encode('utf-8'))
    print(client.recv(1024).decode('utf-8'), "{} 번".format(i+1))

client.close()

 

 

728x90
반응형