def _monitor_clients(self):
        while self.is_running:
            time.sleep(self.wait_term)
            now = time.time()

            with self.lock_clients:
                for client in list(self.clients):
                    try:
                        with client:
                            if client.state == 2:
                                return

                            if client.last_receive_time is None or int(
                                    abs(now - client.last_receive_time)
                            ) > self.wait_term:
                                # 클라이언트의 마지막 수신 시각과 현재 시각을 비교해  heartbeat 전송 주기가 돌아오기 전까지 데이터가 수신한 적이 있는지 확인
                                if client.wait_count == self.max_wait_count:
                                    """
                                    클라이언트가 최대 heartbeat 허용 횟수를 넘긴 상태라면 연결이 끊긴 상태라고 판단하고 예외를 발생시켜 except 부분에서 클라이언트
                                    종료 처리
                                    """
                                    raise Exception
                                else:
                                    # 허용 횟수를 넘기지 않은 상태라면 heartbeat 메시지 전송 후 heartbeat 전송 횟수를 1 증가 시킴
                                    send_message(HEARTBEAT, self.host, client)
                                    client.wait_count += 1
                    except Exception as e:
                        with client:
                            if client.state != 2:
                                client.close()
                                EventManager.call_handler(
                                    DISCONNECTED_CLIENT_EVENT, client=client)
    def _accept_client(self):
        channel: socket.socket
        address: tuple

        channel, address = self._server_socket.accept()

        if len(self.clients) != self.max_client:
            client = Client(address, channel)
            # 소켓을 유용하고 편하게 사용하기 위해 Client 래퍼 객체로 생성
            try:
                self._sel.register(client.channel, selectors.EVENT_READ,
                                   client)  # selectors 이벤트 등록
                self.clients[client] = client
                # 클라이언트 리스트 등록

                EventManager.call_handler(CONNECT_CLIENT_EVENT, client=client)
            except socket.error as e:
                # todo: (try-except) 이제 이벤트 헨들러는 개별 스레드에서 처리하므로 try-except 필요가 없음
                with client:
                    if client != 2:
                        client.close()
        else:
            # 최대 클라이언트 연결 수를 넘어갔을 경우 꽉 찼다는 메시지르 보내고 연결 종료
            channel.sendall(make_message(FULL_CONN, self.host, address[0]))
            channel.close()
    def _receive_client_message(self, client: Client):
        try:
            with client:

                client.last_receive_time = time.time()
                client.wait_count = 0
                # 수신 한 경우 heartbeat 누적 수를 초기화
                # todo: Cleint receive 함수 내부에 처리할것

                header_bytes = client.receive(13)
                # 헤더 사이즈 만큼 버퍼에서 가져옴
                # todo: 사이즈가 작긴 하지만 이 부분도 아래 BODY 데이터를 가지고 오는 것처럼 처리를 해줘야함 (Client receive 함수 내에 처리)

                if not header_bytes:
                    if client.state != 2:
                        client.close()
                        EventManager.call_handler(DISCONNECTED_CLIENT_EVENT,
                                                  client=client)
                    # todo: 이벤트 호출자가 제어하지 않고, 함수 안에서 실행을 제어하도록 변경
                    #   예) 클라이언트 연결 이벤트에서 헨들러 A가 실행할때 어떠한 이유로 클라이언트를 종료시킨 경우 다음 번에 실행될
                    #   (이벤트에 대한 헨들러들이 순차적으로 실행됨) 클라이언트 연결 이벤트 헨들러 B가 실행 되면 안되므로
                    return

                header = Header.decode(header_bytes)

                if not header:
                    return

                body_bytes = client.receive(header.SIZE)
                # body 크기는 가변 적이므로 header에서 body 사이즈를 알아낸 후 버퍼에서 가져옴

                while len(body_bytes) < header.SIZE:
                    body_bytes += client.receive(header.SIZE - len(body_bytes))
                # 서버 상황상 명시한 사이즈 만큼 데이터를 가지고 온다는 보장이 없으므로, 완전할때까지 버퍼에서 가져옴

                receive_message(client, Message(header, body_bytes))

        except Exception as e:
            # 연결 혹은 받아온 데이터에 문제가 있으면 연결을 끊는거로 처리하고 있음
            with client:
                if client.state != 2:
                    client.close()
                    EventManager.call_handler(DISCONNECTED_CLIENT_EVENT,
                                              client=client)