Esempio n. 1
0
class ClientHandler:

    LOGIN_MSG = 'Choose a nickname.'
    HELLO_MSG = 'You are in, {}!'
    NICK_TAKEN_MSG = 'Nickname {} is taken, choose another one.'

    SHUTDOWN_MSG = 'Server shut down and you were disconnected.'

    def __init__(self, sock, addr, server):
        self.server = server
        self.conn = Connection(sock, addr)
        self.inbox = Queue(maxsize=MAX_CLIENT_QUEUE)
        self.nickname = None
        self.channel = None

    @property
    def addr(self):
        return self.conn.addr

    def init(self):
        try:
            self.conn.send_msg(self.LOGIN_MSG)

            while True:
                try:
                    nickname = self.conn.recv_msg()

                    self.server.register_client(nickname, self)
                    self.server.addr_client[self.addr] = self

                    self.nickname = nickname
                    self.conn.send_msg(self.HELLO_MSG.format(nickname))
                    break
                except NickTakenError:
                    self.conn.send_msg(self.NICK_TAKEN_MSG.format(nickname))
        except OSError:
            self.shutdown()

        # Connection fully established.
        self.server.subscribe(self.nickname, 'default')
        self.channel = self.server.channels['default']
        self.in_channel()

    def shutdown(self):
        try:
            self.conn.send_msg(self.SHUTDOWN_MSG)
            self.conn.close()
        except OSError:
            pass  # yeah, really

        self.channel.unsub(self.nickname)
        self.server.remove_client(self.nickname)

    def in_channel(self):
        receiver = threading.Thread(target=self.process_inbox, daemon=True)
        receiver.start()

        try:
            while True:
                msg = self.conn.recv_msg()
                msg = '{}: {}'.format(self.nickname, msg)
                self.channel.publish(('tcp', msg), self.nickname)
        except ConnectionError:
            self.shutdown()

    def process_inbox(self):
        try:
            while True:
                kin, msg = self.inbox.get()
                if kin == 'udp':
                    send_udp(msg, self.addr)
                else:
                    self.conn.send_msg(msg)
        except ConnectionError:
            self.shutdown()

    def push(self, msg):
        self.inbox.put(msg)

    def handle_udp(self, msg):
        self.channel.publish(('udp', msg), self.nickname)
Esempio n. 2
0
class Client:
    def __init__(self, server_host='127.0.0.1', server_port=8000, client_host='127.0.0.1', client_port=8001):
        self.server_addr = (server_host, server_port)
        self.client_addr = (client_host, client_port)
        self.conn = None

    def run(self):
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
            s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
            s.bind(self.client_addr)
            s.connect(self.server_addr)
            self.conn = Connection(s, self.server_addr)

            receiver = threading.Thread(target=self.receive, daemon=True)
            receiver.start()
            udp_receiver = threading.Thread(target=self.receive_udp, daemon=True)
            udp_receiver.start()

            try:
                while True:
                    msg = input()

                    if msg == 'U' or msg == 'M':
                        with open('ascii.txt', 'r', encoding='ascii') as ascii_art:
                            content = ascii_art.read()

                        if msg == 'U':
                            addr = self.server_addr
                        else:
                            addr = MULTICAST_ADDR
                        send_udp(content, addr, self.client_addr)
                    else:
                        self.conn.send_msg(msg)
            except KeyboardInterrupt:
                print('Received Ctrl+C.')
            except ConnectionError:
                print('Connection to server closed.')

    def receive(self):
        try:
            while True:
                msg = self.conn.recv_msg()
                print('>>> {}'.format(msg))
        except ConnectionError:
            self.conn.close()

    def receive_udp(self):
        with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as u_sock:
            with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as m_sock:
                u_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                u_sock.bind(self.client_addr)

                host = socket.gethostbyname(socket.gethostname())
                m_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
                m_sock.setsockopt(socket.SOL_IP, socket.IP_ADD_MEMBERSHIP,
                                  socket.inet_aton(MULTICAST_ADDR[0]) + socket.inet_aton(host))
                m_sock.bind(MULTICAST_ADDR)

                ev_loop = select.epoll()
                u_fd, m_fd = u_sock.fileno(), m_sock.fileno()
                ev_loop.register(u_fd, select.EPOLLIN)
                ev_loop.register(m_fd, select.EPOLLIN)

                try:
                    while True:
                        events = ev_loop.poll()
                        for file_no, event in events:
                            if event | select.EPOLLIN:
                                if file_no == u_fd:
                                    msg = u_sock.recv(MAX_UDP_SIZE)
                                else:
                                    msg, addr = m_sock.recvfrom(MAX_UDP_SIZE)
                                    if addr == self.client_addr:
                                        continue
                                print(msg.decode())
                except ConnectionError:
                    self.conn.close()