본문 바로가기
네트워크

python socket select 함수 이해하기

by meanjung 2021. 7. 26.

멀티 플렉싱

하나의 통신 채널을 통해 둘 이상의 데이터를 전송하는데 사용되는 기술

즉, 하나의 서버에서 여러 클라이언트를 모두 처리하는 것

 

하나의 서버에서 시그널(fd)를 통해 여러 클라이언트와 모두 데이터를 주고받는 것

 

select 함수

특징

- 한 곳에 여러 파일 디스크립터들을 모아놓고 동시에 관찰할 수 있다.

 

 

관찰할 수 있는 event

1. 수신한 데이터를 갖고 있는 소켓이 있는가? - read

2. 블로킹되지 않고 데이터의 전송이 가능한 소켓이 있는가? - write

3. 예외상황이 발생한 소켓은 무엇인가? - except

 

readable, writable, exceptionable = select(readList, writeList, exceptList, timeout)

readable : readList 내에 읽을 준비가 된 소켓들 반환

writable, exceptionable 도 마찬가지 개념

 

 

그렇다면, 읽을 준비가 되었다는 것은 언제일까?

즉, readable로 반환될 때는 어느 상황일 때인가?

         - 출처 : https://www.oreilly.com/library/view/python-standard-library/0596000960/ch07s03.html

         - 내 생각, 틀릴 수 있음

  1. listen에 누군가 connect할 때if rsocket is serverSocket (in server.py)
  2. remote에서 data가 도착할 때if rsocket is not serverSocket (in server.py)/ serverSocket이 들어왔을 때(in client.py)
  3. socket이 닫히거나 reset 됐을 때

 

어떤 흐름으로 select 함수를 호출해야할까?

1. 파일 디스크립터 설정

파일 디스크립터를 list같이 모아두며 탐색

 

2. 검사 범위 지정

가장 큰 fd가 무엇인지 알고 탐색하는 것이 효율적이다.

 

3. 타임아웃 설정

fd의 변화를 언제까지 기다릴 것인지 결정

 

4. select 함수 호출

 

5. 호출 결과 확인

어떤 fd에서 어떤 시그널이 왔는지 확인한 뒤 작업을 진행해야 한다.


내가 깨달은 점 * 틀린 개념일 수도 있습니다

server.py 하나 있고, client.py를 여러 vm에 설치해서 server에 접속해봤다.

 

server.py

from socket import *
from select import *
import sys
from time import ctime

HOST = '0.0.0.0'
PORT = 8000
BUFSIZE = 1024
ADDR = (HOST, PORT)

server = socket(AF_INET, SOCK_STREAM)
server.bind(ADDR)
server.listen(10)
connection_list = [server]

print("===============================================")
print("server start. PORT :", PORT)
print("===============================================")

while connection_list:
    try:
        rsocket, wsocket, esocket = select(connection_list, [], [], 10)
        print('rsocket : ', rsocket)
        print('wsocket : ', wsocket)
        print('esocket : ', esocket)
        for rsckt in rsocket:
            if rsckt is server:
                client, clientAddr = server.accept()
                print("client accessed (%s : %s)"%(client, clientAddr))
                connection_list.append(client)
                client.send("new visit, client".encode())
            else:
                data = rsckt.recv(BUFSIZE)
                if data:
                    print("%s got data : %s"%(rsckt, data))
                    rsckt.send("I\'v got data, client".encode())
                else:
                    connection_list.remove(rsckt)
                    rsckt.close()
                    print("connection refused")
    except KeyboardInterrupt:
        server.close()
        sys.exit()

여기서 가장 이해가 안갔던 부분은 if rsckt is serverelse를 나눠서 표현한 부분.

 

"아마도"

 

if rsckt is server : client가 serverSocket에 접속했음. 때문에 client, clientAddr을 server에게서 accept할 수 있는 것임

listen에 누군가 connect했기 때문에 readable

 

else : client가 데이터를 보내서 받는다. 

remote에서 data가 도착했기 때문에 readable

 

 

 

client.py

from socket import *
from select import *
import sys

HOST = "127.0.0.1"
PORT = 8000
BUFSIZE = 1024
ADDR = (HOST, PORT)

client = socket(AF_INET, SOCK_STREAM)
client.connect(ADDR)

print("Connected to server(%s:%s)"%ADDR)

def prompt():
    sys.stdout.write(" >> ")
    sys.stdout.flush()

while True:
    try:
        connection_list = [sys.stdin, client]
        rsocket, wsocket, esocket = select(connection_list, [], [], 10)
        for sckt in rsocket:
            if sckt is client:
                data = sckt.recv(BUFSIZE)
                if not data:
                    print("connection refused from server(%s:%s)"%ADDR)
                    client.close()
                    sys.exit()
                else:
                    print("server socket : ", str(sckt))
                    print("%s"%data)
                    prompt()
            else:
                print("What is this socket : ", str(sckt))
                message = input()
                client.send(message.encode())
    except KeyboardInterrupt:
        client.close()
        sys.exit()

if sckt is client : server socket이 데이터를 보냈음.

☞ remote에서 data가 도착했기 때문에 readable

else : sys.stdin일 때, 여기 else 부분이 실행됨.

왜 readable일까...


socket 통신에 대한 이해도 필요하고, 

select 함수가 동작하는 방식도 이해해야 한다.

 


참고

https://steelkiwi.com/blog/working-tcp-sockets/

 

How to Work with TCP Sockets in Python (with Select Example)

This article is about low level work with TCP sockets in Python. It describes standard ways to work with sockets: blocking and asynchronous.

steelkiwi.com

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=tenque&logNo=221077725482 

 

select() 함수를 이용한 비동기 네트워크 프로그램

[서버 프로그램] # socket 과 select 모듈 임포트 from socket import * from select import * import sys ...

blog.naver.com

https://scienceofdata.tistory.com/entry/Python-select-%ED%95%A8%EC%88%98%EB%A5%BC-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EA%B0%84%EB%8B%A8%ED%95%9C-%EC%97%90%EC%BD%94-%EC%84%9C%EB%B2%84%ED%81%B4%EB%9D%BC%EC%9D%B4%EC%96%B8%ED%8A%B8-%EC%98%88%EC%A0%9C

 

Python select 함수를 이용한 간단한 에코 서버/클라이언트 예제

select 함수를 이용한 간단한 에코 서버/클라이언트 예제이다 서버 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48..

scienceofdata.tistory.com


더 읽어볼거리

https://velog.io/@hyeseong-dev/%EC%86%8C%EC%BC%93%ED%86%B5%EC%8B%A0-%ED%8C%8C%EC%9D%B4%EC%8D%AC-%EC%B1%84%ED%8C%85%EC%95%B1

 

[소켓통신] 파이썬 채팅앱

server.pyclient.py(poetry.lock, pyproject.toml 파일은 poetry를 이용하여 가상환경을 구성하여 나온 파일들입니다. 다른 가상환경을 사용해도 무방해요.)twistednames

velog.io

https://m.blog.naver.com/heennavi1004/222051331011

 

[network] 파이썬 소켓 통신

파이썬 소켓 통신/ 참고 https://medium.com/python-pandemonium/python-socket-communication-e10b39225a4...

blog.naver.com

 

댓글