멀티쓰레딩을 이용하여 여러 개의 클라이언트를 받을 수 있는 소켓 서버를 파이썬으로 구현해 보았습니다. 



server.py

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

import threading
import SocketServer
import socket
import sys


class CustomException(Exception):
    """
    Exception 클래스를 상속한 클래스를 만든다
    """
    def __init__(self, value):
        """
        생성할때 value 값을 입력 받음
        """
        self.value = value

    def __str__(self):
        """
        생성할때 받은 value 값을 확인
        """
        return self.value


def raise_exception(err_msg, ip_addr=None):
    """
    예외를 발생하는 함수
    """
    raise CustomException(err_msg)


def print_delimiter():
    print("="*20)


class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        """
        클라이언트와 연결될 때 호출되는 함수
        상위 클래스에는 handle() 메서드가 정의되어 있지 않기 때문에
        여기서 오버라이딩을 해야함
        """
        cur_thread = threading.current_thread()
        print("{} was started for {}"
              .format(cur_thread.getName(), self.client_address[0]))

        while True:
            try:
                self.recv_data = self.request.recv(1024).strip()

                # :/quit 를 입력하거나 데이터가 없다면 루프를 종료
                if self.recv_data == ":/quit" or not self.recv_data:
                    print_delimiter()
                    raise_exception("{} was gone".format(self.client_address[0]))

            except NameError as e:
                print "{0} got an error : {1}".format(self.client_address[0], e)
                self.request.send("Bye")
                break

            except CustomException as e:
                print e
                self.request.send("Bye")
                break

            print "{} wrote:".format(self.client_address[0]),
            print self.recv_data

            # 영어의 소문자 데이터를 receive 하면 대문자로 변환해 send
            self.request.sendall(self.recv_data.upper())

        print("{} was ended for {}"
              .format(cur_thread.getName(), self.client_address[0]))
        print_delimiter()


class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
    pass


if __name__ == "__main__":
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "0.0.0.0", 3000

    # 소켓 객체 생성
    try:
        server = ThreadedTCPServer((socket.gethostbyname(HOST), PORT), ThreadedTCPRequestHandler)

    except socket.error, msg:
        print "Bind failed. Closing..."
        print "Error code: %s \nError Message: %s"\
          % (str(msg[0]), msg[1])
        sys.exit()

    print "Socket bound on {}".format(PORT)
    ip, port = server.server_address

    # 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)
    # Exit the server thread when the main thread terminates
    server_thread.daemon = True
    server_thread.start()
    print "Server loop running in thread:", server_thread.name

    server.serve_forever()

    server.shutdown()
    server.server_close()



client.py

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

import socket
import sys

HOST, PORT = "192.168.228.128", 8080
# data = "This will be nickname"  # 실제 서비스에는 닉네임을 전송하자

try:
    # 소켓을 생성 (SOCK_STREAM 은 TCP 소켓을 의미)
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.connect((HOST, PORT))

except socket.error, msg:
    print "Failed to create socket. Error code: %s \nError Message: %s"\
          % (str(msg[0]), msg[1])
    sys.exit(0)
print "Socket created"

# input 값이 :/quit 일 때까지 데이터 입력 및 전송 반복
# :/quit 를 입력하면 socket 종료
while True:

    try:
        data = raw_input("Input : ")

        if data == ":/quit" or not data:
            sock.close()
            break

        try:
            # 서버에 연결하고 데이터를 전송
            sock.sendall(data + "\n")

            # 데이터를 수신하고 소켓 연결을 닫음
            received = sock.recv(1024)

        finally:
            print "Sent:     {}".format(data)
            print "Received: {}".format(received)

    except KeyboardInterrupt as e:
        print e
        data = ":/quit"

sock.close()


블로그 이미지

NCookie

,