# L-32 MCS 275 Fri 31 Mar 2017 : mtserver.py
"""
Illustration of multithreaded server.
"""

from socket import socket as Socket
from socket import AF_INET, SOCK_STREAM
from threading import Thread

class Handler(Thread):
    """
    Defines handler threads.
    """
    def __init__(self, n, sock, buf):
        """
        Name of handler is n, server
        socket is sock, buffer size is buf.
        """
        Thread.__init__(self, name=n)
        self.srv = sock
        self.buf = buf

    def run(self):
        """
        Handler accepts connection,
        prints message received from client.
        """
        handler = self.getName()
        server = self.srv
        buffer = self.buf
        client, client_address = server.accept()
        print(handler + ' accepted request from ', \
            client_address)
        print(handler + ' waits for data')
        data = client.recv(buffer).decode()
        print(handler + ' received ', data)

def connect(nbr):
    """
    Connects a server to listen to nbr clients.
    Returns the server socket.
    """
    hostname = ''      # to use any address
    portnumber = 11267 # number for the port
    server_address = (hostname, portnumber)
    server = Socket(AF_INET, SOCK_STREAM)
    server.bind(server_address)
    server.listen(nbr)
    return server

def main():
    """
    Prompts for number of connections,
    starts the server and handler threads.
    """
    nbr = int(input('give the number of clients : '))
    buf = 80
    server = connect(nbr)
    print('server is ready for %d clients' % nbr)
    handlers = []
    for i in range(nbr):
        handlers.append(Handler(str(i), server, buf))
    print('server starts %d threads' % nbr)
    for handler in handlers:
        handler.start()
    print('waiting for all threads to finish before closing socket ...')
    for handler in handlers:
        handler.join()
    server.close()

if __name__ == "__main__":
    main()
