Socket issue when using threads
Question: I've been working on a python game in my spare time, and I've run into a
problem. I'm working with sockets using the basic threads module, and it works
fine when I connect to the server file with one client. But more than that,
and any that connect after the first freezes up the server and the first
client.

Here is the code for the server

    
    
    import socket
    import random
    import thread
    from saveState import Save
    from grid import Grid   
    import time
    players = 0
    save = Save()
    grid = Grid()
    
    def ready(c):
        ready = raw_input("Are you ready to play?\n")
        if(ready == "yes" or ready == "y"):
            grid.makeGrid() 
            c.send("ready")
    def clientThread(conn,players):
    
        while True:
            print "taking requests"
            request = conn.recv(1024)
            segments = request.split(",,")
            if(segments[0] == "0" and players<200):
                print "registering player", addr
                serial = random.choice(list(range(999999)))
                conn.send("{}".format(serial))
                save.players[serial] = segments[2:]
                print save.players[serial][9]
                players+=1
            elif(segments[0] == "3"):
                if(segments[2] == "land"):
                    conn.send("{},,{},,{},,{}".format(grid.getLandType(int(save.players[serial][9]),int(save.players[serial][10])), grid.getDesc(int(save.players[serial][9]),int(save.players[serial][10])),int(save.players[serial][9]),int(save.players[serial][10])))
            elif(segments[0]=="2"):
                if(segments[2]=="playerX" and int(segments[3])==-1):
                    save.players[serial][9] = int(save.players[int(serial)][9])-1 
                elif(segments[2]=="playerX"):
                    save.players[serial][9] = int(save.players[int(serial)][9])+1 
                if(segments[2]=="playerY" and int(segments[3])==-1):
                    save.players[serial][10] = int(save.players[int(serial)][10])-1 
                elif(segments[2]=="playerY"):
                    save.players[serial][10] = int(save.players[int(serial)][10])+1 
            elif(segments[0]=="4"):
                alreadySent = []
                for m in grid.monsters:
                    if(m.X==save.players[int[segment[1]]][9] and m.Y==save.players[int[segment[1]]][10] and alreadySent[m]==False):
                        conn.send("{},,{}".format(m.name, True))
                    elif(time.clock == 60*60*(12+8)):
                        conn.send("{},,{}".format("You see the sun set on the horizon. Monsters will be more aggressive now.", False))
            else:       
                print "sorry, there is an inconsistency in the request or the queue is full."
    
    
    
    try:
        #start up socket
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        name = socket.gethostbyname(socket.gethostname())
        print name
        port = input("select port\n")
        s.bind((name, port))
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        #listen for any attempts to connect to the api
        #if anyone connects, give them a serial number and add their data to a storage file
        while True: 
            s.listen(5)
            c,addr = s.accept()
            thread.start_new_thread(ready,(c,))
            thread.start_new_thread(clientThread,(c, players))
        conn.close
        sock.close
    except socket.error:
        print " either the server port is closed or in use. try again"
    

and the client

    
    
    import random
    from grid import Grid
    from player import Player
    from descriptions import Descriptions
    import socket
    import time
    import thread
    description = Descriptions()
    
    def descisionHandler(s,serial):
        while True:
            s.send("{},,{},,{}".format(3,serial,"land"))
            response = s.recv(1024).split(",,")
            print "you are on a {} tile \n {} \n {} \n {}".format(response[0], response[1],response[2], response[3])
            action=raw_input("What Will You Do?\n")
            try:
                if(action == "west" and player.locX>0):
                    s.send("{},,{},,{},,{}".format(2,serial,"playerX",-1))
                    time.sleep(0.5)
                elif(action == "east" and player.locX<199):
                    s.send("{},,{},,{},,{}".format(2,serial,"playerX",1))
                    time.sleep(0.5)
                elif(action == "north" and player.locY>0):
                    s.send("{},,{},,{},,{}".format(2,serial,"playerY",-1))
                    time.sleep(0.5)
                elif(action == "south" and player.locY<199):
                    s.send("{},,{},,{},,{}".format(2,serial,"playerY",1))
                    time.sleep(0.5)
              #  elif(action == "attack" and monster_data[1]):
                  #  print "The {} wakes up! A battle begins!".format(monster_data[0])
                elif(action == "profile"):
                    print " You are {} \n  {} \n your role is {} \n you have an attack of {} \n a defense of {} \n a speed of {} \n and {} hitpoints \n attacks: {} \n you are located at  {} {}".format(player.name,
                        player.backstory,player.role,player.attack,player.defense,player.speed, player.hitpoints, player.attacks, player.locX, player.locY)
                elif(action == "exit"):
                    break
            except IndexError:
                pass
    
    def eventHandler(s,serial):
        while True:
            s.send("{},,{}".format(4,serial))
            response = s.recv(1024).split(",,")
            print response[0]
            return bool(response[1])
    
    
    
    while True:
        try:
            print "\nWelcome to Overseer! We need a few things before we begin\n"
            name = raw_input("What is your name?\n")
            backstory = raw_input("What is in your past: choose one \n chosen \n magician \n poet\n")
            role = raw_input("what is your class: choose one \n Warrior \n Mage \n Rougue \n Bard\n")
            player = Player(name,description.player_backstory[backstory], role, 5,5,5,10, {"scrap": 10}, random.choice(list(range(200))), random.choice(list(range(200))))
    
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            host = raw_input("what host are you connecting to?")
            port = input("what port?\n")
    
            s.connect((host,port))
            print "connection successful." 
            time.sleep(5)
            s.send("{},,{},,{},,{},,{},,{},,{},,{},,{},,{},,{},,{},,{}".format(0,0,name,backstory,role,5,5,5,5,10,player.attacks,player.locX,player.locY))
            serial = s.recv(1024)
            print "You're serial number is {}".format(serial)
            while(s.recv(1024) != "ready"):
                pass
            break
        except socket.error:
            print "server is not running or is busy. please try again."
    
    eventThread = thread.start_new_thread(eventHandler,(s,serial))
    descisionThread = thread.start_new_thread(descisionHandler,(s,serial))
    
    while 1:
        pass
    

I did a bit of research and my best guess is that I need to use locks from the
threading module, but I'm not sure. any suggestions?

Thanks in advance!


Answer: So the issue was the console input, as theSmallNothing said. There wasn't
really a way around this limitation without serious hacking, so I proposed to
improvise. My solution was to create a web app with python instead of using a
console. There were a few advantages to this.

  * the server can handle multiple inputs at a time easily
  * things can happen while input is being entered(the solution to my problem)
  * no files need be downloaded for the user as everything can be accessed simply by entering the web address.

While not a perfect solution, sometimes finding an alternative is the next
best thing.

Thanks all for your awesome help!

