4

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!

7
  • I don't know the answer, but you should use the threading module instead of thread, it's a higher-level interface. Commented Dec 8, 2014 at 18:13
  • To just answer your question, s.listen(5) shouldn't be called more than once on setup, move it out of the while loop. Only s.accept() should be called for every client. Commented Dec 8, 2014 at 18:20
  • conn.recv could read partial messages, and your code breaks. Commented Dec 8, 2014 at 18:31
  • @theSmallNothing I actually had it out of the while loop while before the problem started. Just to check, I moved it back out again and the problem persists. Also Daniel, what do you mean by partial messages. I don't get any errors, everything just stops Commented Dec 8, 2014 at 18:45
  • Thats interesting, I just tested it out and thats what caused my program to stop in exactly the way you described. Unfortunately there are a few bugs in the program I can see but the next most likely is the raw_input in the ready function, due to the way many console applications work raw_input will block all threads until some input is entered therefore you shouldn't be putting it a thread. Commented Dec 8, 2014 at 19:06

1 Answer 1

0

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!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.