# L-29 MCS 275 Fri 21 Mar 2008 : mtnserver.py

# Illustration of multithreaded server,
# n threads will handle m requests.

from socket import *
from threading import *
import time

class Handler(Thread):
   """
   Defines handler threads.
   """
   def __init__(self,n,s,b):
      """
      Name of handler is n, server
      socket is s, buffer size is b.
      """
      Thread.__init__(self,name=n)
      self.sv = s
      self.bf = b

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

def connect(n,b):
   """
   Connects a server to listen to n clients,
   using buffer size b.  Returns the socket.
   """
   hostname = ''   # to use any address
   number = 11267  # number for the port
   buffer = b      # size of the buffer
   server_address = (hostname, number)
   server = socket(AF_INET, SOCK_STREAM)
   server.bind(server_address)
   server.listen(n)
   return server

def restart(T,s,i):
   """
   Deletes the i-th dead thread from T
   and inserts a new thread at position i.
   The socket server is s.  Returns new T.
   """
   del T[i]
   T.insert(i,Handler(str(i),s,80))
   T[i].start()
   return T

def manage(T,m,s):
   """
   Manages threads in T, restarts threads
   until m requests have been handled.
   The socket server is s.
   """
   cnt = 0; n = len(T); dead = []
   while cnt < m:
      time.sleep(2)
      for i in range(0,n):
         if i in dead:
            pass
         elif T[i].isAlive():
            print i, 'is alive, cnt =', cnt
         else:
            cnt = cnt + 1
            print '%d handled request %d' \
                % (i,cnt)
            if cnt >= m:
               break
            elif cnt <= m-n:
               print 'restarting', i
               T = restart(T,s,i)
            else:
               dead.append(i)

def main():
   """
   Prompts for number of connections,
   starts the server and handler threads.
   """
   n = input('give #clients : ')
   m = input('give #requests : ')
   server = connect(n,80)
   print 'server is ready for %d clients' % n
   T = []; C = []
   for i in range(0,n):
      T.append(Handler(str(i),server,80))
   C.append(0)
   print 'server starts %d threads' % n
   for t in T: t.start()
   manage(T,m,server)
   server.close()

if __name__ == "__main__": main()
