Python - socketserver와 threading을 이용한 채팅서버 구축
import socketserver, threading, socket
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024).decode()
cur_thread = threading.current_thread()
response = "{}: {}".format(cur_thread.name, data)
self.request.sendall(response.encode('utf-8'))
# handle함수는 클라이언트로부터 request가 왔을 때 동작하는 함수입니다.
# socketserver.BaseRequestHandler 클래스를 상속했다면 반드시 사용자가 override를 하여 실행할 동작을 정의해 주어야합니다.
# data는 클라이언트가 보낸 데이터(버퍼사이즈1024)를 보유하고 있습니다.
# 현재 쓰레드를 호출하고 이를 cur_thread라는 변수에 대입합니다.
# cur_thread.name으로 현재 쓰레드의 이름 (쓰레드 생성시 이름을 지정할 수 있으며 지정하지 않을경우 기본적으로 'Thread-정수(1부터시작)'이 기본값이 됩니다.
# 따라서 response는 현재 쓰레드 이름과 클라이언트가 수신한 데이터를 문자열로 보관하는 변수이고
# 이를 인코딩 하여 sendall메소드를 통해 접속한 모든 클라이언트에게 보내주게 됩니다.
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
# socket서버의 ThreadingMixIn클래스와 TCP클래스를 상속받은 새로운 클래스 ThreadedTCPServer를 새롭게 생성했습니다.
# 이제 ThreadedTCPServer는 두 클래스의 메소드를 사용할 수 있습니다.
def client(ip, port, message):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port))
try:
sock.send(message.encode('utf-8'))
response = sock.recv(1024).decode()
print("Received: {}".format(response))
finally:
sock.close()
# client라는 함수를 정의하며 인자로 ip, port, message를 받습니다.
# 소켓의 기본값이 되는 ipv4, TCP로 소켓을 생성하고 이를 sock 변수라고 지칭했습니다.
# 변수로 받은 ip, port에 소켓이 연결합니다.
# 이 후 변수로 받은 message를 인코딩하여 지정한 소켓으로 전송합니다 (여기서는 서버)
# 서버로부터 받은 응답을 response에 담습니다.
# 그리고 받은 데이터를 디코딩한 뒤 print합니다.
# 구문이 정상적으로 실행되면 소켓을 닫습니다. < 소켓은 항상 마지막에 닫아주어야 합니다.
if __name__ == "__main__":
HOST, PORT = "localhost", 0
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
# HOST와 PORT를 각각 localhost, 미사용중인 아무포트로 배정했습니다.
# server라는 객체는 위에서 정의한 ThreadedTCPServer의 인스턴스이며, ????에게 인자를 전달합니다.
# server_address 메소드는 ThreadedTCPServer 인스턴스의 ip와 포트를 반환합니다. 각각을 ip, port 변수에 담습니다.
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# server_thread라는 객체를 만들었습니다. 이 쓰레드에서는 server.serve_forever라는 메소드를 실행할 것입니다.
# serve_forever는 socketserver에 내장된 메소드로, 서버를 실행합니다.
server_thread.daemon = True
server_thread.start()
print("Server loop running in thread:", server_thread.name)
client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3")
server.shutdown()
server.server_close()
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = self.request.recv(1024).decode()
cur_thread = threading.current_thread()
response = "{}: {}".format(cur_thread.name, data)
self.request.sendall(response.encode('utf-8'))
# handle함수는 클라이언트로부터 request가 왔을 때 동작하는 함수입니다.
# socketserver.BaseRequestHandler 클래스를 상속했다면 반드시 사용자가 override를 하여 실행할 동작을 정의해 주어야합니다.
# data는 클라이언트가 보낸 데이터(버퍼사이즈1024)를 보유하고 있습니다.
# 현재 쓰레드를 호출하고 이를 cur_thread라는 변수에 대입합니다.
# cur_thread.name으로 현재 쓰레드의 이름 (쓰레드 생성시 이름을 지정할 수 있으며 지정하지 않을경우 기본적으로 'Thread-정수(1부터시작)'이 기본값이 됩니다.
# 따라서 response는 현재 쓰레드 이름과 클라이언트가 수신한 데이터를 문자열로 보관하는 변수이고
# 이를 인코딩 하여 sendall메소드를 통해 접속한 모든 클라이언트에게 보내주게 됩니다.
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
# socket서버의 ThreadingMixIn클래스와 TCP클래스를 상속받은 새로운 클래스 ThreadedTCPServer를 새롭게 생성했습니다.
# 이제 ThreadedTCPServer는 두 클래스의 메소드를 사용할 수 있습니다.
def client(ip, port, message):
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((ip, port))
try:
sock.send(message.encode('utf-8'))
response = sock.recv(1024).decode()
print("Received: {}".format(response))
finally:
sock.close()
# client라는 함수를 정의하며 인자로 ip, port, message를 받습니다.
# 소켓의 기본값이 되는 ipv4, TCP로 소켓을 생성하고 이를 sock 변수라고 지칭했습니다.
# 변수로 받은 ip, port에 소켓이 연결합니다.
# 이 후 변수로 받은 message를 인코딩하여 지정한 소켓으로 전송합니다 (여기서는 서버)
# 서버로부터 받은 응답을 response에 담습니다.
# 그리고 받은 데이터를 디코딩한 뒤 print합니다.
# 구문이 정상적으로 실행되면 소켓을 닫습니다. < 소켓은 항상 마지막에 닫아주어야 합니다.
if __name__ == "__main__":
HOST, PORT = "localhost", 0
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
# HOST와 PORT를 각각 localhost, 미사용중인 아무포트로 배정했습니다.
# server라는 객체는 위에서 정의한 ThreadedTCPServer의 인스턴스이며, ????에게 인자를 전달합니다.
# server_address 메소드는 ThreadedTCPServer 인스턴스의 ip와 포트를 반환합니다. 각각을 ip, port 변수에 담습니다.
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# server_thread라는 객체를 만들었습니다. 이 쓰레드에서는 server.serve_forever라는 메소드를 실행할 것입니다.
# serve_forever는 socketserver에 내장된 메소드로, 서버를 실행합니다.
server_thread.daemon = True
server_thread.start()
print("Server loop running in thread:", server_thread.name)
client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3")
server.shutdown()
server.server_close()
이해가 안되는 것....
- handle 메소드에 왜 쓰레드를 넣는것인지 이해가 잘 안됩니다.
- 여기서 서버 실행은 서브쓰레드가 하는건가요?
- server 인스턴스는 (HOST,PORT), ThreadedTCPRequestHandler 인자를 누구한테 주는건가요??
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
.
.
.
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
이 구문이요
댓글
댓글 쓰기