05-16 05:32
Recent Posts
Recent Comments
관리 메뉴

miinsun

[Network/Python]파이썬 소켓 통신 본문

Infra/Network

[Network/Python]파이썬 소켓 통신

miinsun 2021. 12. 2. 15:39

 

소켓은 connect가 완료되면, 응답을 읽은 다음 해당 소켓은 파괴된다.

클라이언트 소켓은 일반적으로 하나의 교환에서만 사용된다.


 

웹 서버에서 소켓 통신 과정

 

1 - 웹서버는 서버 소켓 생성

 

서버 소켓 객체 생성

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

 

소켓을 외부 세계에서 볼 수 있도록 gethostname() 사용

serversocket.bind((socket.gethostname(), 80))
  • 'localhost'를 사용하면 같은 기계 내에서만 소켓을 갖게 됨으로 주의하자.
  • 낮은 포트의 번호 80은 잘 알려진 서비스인 HTTP, SNMP를 예약하기 위해서이다.

 

listen은 외부 연결을 거부하기 전에 최대 5개의 연결 요청을 큐에 넣는다.

serversocket.listen(5)

 

 

2 - 웹 서버의 메인 루프를 작성

웹 서버는 어떠한 송. 수신을 하지 않고, 그저 클라이언트 소켓을 생성한다.

각 client 소켓은 우리가 Bind 한 호스트와 포트로 connect()를 수행하는 다른 클라이언트 소켓의 응답으로 만들어진다. 웹서버는 클라이언트 소켓을 만들며 더 많은 연결을 기다린다.

while True:

# 외부에서 연결을 수락
(clientsocket, address) = serversocket.accept()

# 클라이언트 소켓에서 무언가 이루어짐
# 이런 경우에는 스레드 서버가 가장 적당하다
ct = client_thread(clientsocket)
ct.run()

 

 

3 - 소켓 사용하기

소켓 통신에는 send, recv가 사용된다. send와 recv는 네트워크 버퍼에서 처리되기 때문에 우리가 넘긴 모든 바이트를 처리하지 않을 수도 있다. 일반적으로 연관된 네트워크 버퍼가 채워지거나(send) 비워지면(recv) 반환된다.

만약 send 또는 recv가 0바이트를 반환한다면, 다른 쪽 소켓이 연결을 닫고 있다는 뜻이다. 더 이상 이 연결에서 데이터를 받지 못하게 된다.

소켓 연결을 재사용하기 위한 방법으로는

  1. 메시지가 고정길이
  2. 구분자로 표시
  3. 메시지의 크기를 표시 하는 방법

등이 있다.

3의 방법이 가장 좋은 방법 이지만 우리는 가장 간단한 해결 책인 1. 고정길이 메시지를 사용할 것이다.

class MySocket:

# 효율성보다는 명확성을 따진 코드

def __init__(self, sock=None):
    if sock is None:
        self.sock = socket.socket(
            socket.AF_INET, socket.SOCK_STREAM)
    else:
        self.sock = sock

def connect(self, host, port):
    self.sock.connect((host, port))

def mysend(self, msg):
    totalsent = 0
    while totalsent < MSGLEN:
        sent = self.sock.send(msg[totalsent:])
        if sent == 0:
            raise RuntimeError("socket connection broken")
        totalsent = totalsent + sent

def myreceive(self):
    chunks = []
    bytes_recd = 0
    while bytes_recd < MSGLEN:
        chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
        if chunk == b'':
            raise RuntimeError("socket connection broken")
        chunks.append(chunk)
        bytes_recd = bytes_recd + len(chunk)
    return b''.join(chunks)

 

 
🛑주의🛑 소켓이 죽을 경우
소켓 연결을 하는 상대방이 close()를 하지 않고 갑자기 다운한다면 소켓이 죽게 된다.
만약 스레드를 사용하고 있었다면, 모든 스레드가 멈추게 된다. 스레드가 죽으면 전체 프로세스가 망하기 때문에 되도록 이런 일은 없도록 주의하자.

 

 

참고: https://docs.python.org/ko/3/howto/sockets.html

'Infra > Network' 카테고리의 다른 글

[Network] TCP TimeOut, TCP 재전송  (0) 2022.07.12
[Network] TCP의 이해  (0) 2022.07.12
[Network/Java] 자바 소켓 통신  (0) 2021.12.03
[Network] TCP와 UDP의 차이  (0) 2021.12.03
[Network] 네트워크 기본 용어  (0) 2021.11.25
Comments