简体   繁体   中英

Python global variable is not updating it's value in threads

So, I have a guess-the-number type of game in python and I made a threaded server to accept multiple clients to play at once. A thing I want to do is with every answer (S-smaller, H-higher, W-winner, L-loser) I send from the server to the client, to also send a message telling the client how many clients are currently connected, hence client_count . The problem is that the first client will always be told that there is 1 client playing, the second one will be told that there are 2 players and so on. The global variable client_count doesn't seem to update over all the threads.

server.py

__author__ = 'emil'

import socket
import threading
import random
import struct
import time

random.seed()
start = 1
stop = 2 ** 17 - 1
my_num = random.randint(start, stop)
print('Server number: ', my_num)
mylock = threading.Lock()
client_guessed = False
winner_thread = 0
e = threading.Event()
e.clear()
threads = []
client_count = 0


def worker(cs):
    global mylock, client_guessed, my_num, winner_thread, client_count, e

    my_idcount = client_count
    print('client #', client_count, 'from: ', cs.getpeername())
    message = 'Hello client #' + \
              str(client_count) + \
              ' ! You are entering the number guess competion now !\n' + \
              'There are currently ' + str(len(threads)) + \
              ' players int game.'
    cs.sendall(bytes(message, 'ascii'))

    players_count_message = "There are currently " + str(client_count) + \
                            " players in game."

    while not client_guessed:
        try:
            cnumber = cs.recv(4)

            if client_guessed:
                break

            cnumber = struct.unpack('!I', cnumber)[0]
            if cnumber > my_num:
                cs.sendall(b'S')
                cs.sendall(bytes(players_count_message, 'ascii'))
            if cnumber < my_num:
                cs.sendall(b'H')
                cs.sendall(bytes(players_count_message, 'ascii'))
            if cnumber == my_num:
                mylock.acquire()
                client_guessed = True
                winner_thread = threading.get_ident()
                mylock.release()

        except socket.error as msg:
            print('Error:', msg.strerror)
            break

    if client_guessed:
        if threading.get_ident() == winner_thread:
            cs.sendall(b'G')
            cs.sendall(bytes(players_count_message, 'ascii'))
            print('We have a winner', cs.getpeername())
            print("Thread ", my_idcount, " winner")
            e.set()
        else:
            cs.sendall(b'L')
            cs.sendall(bytes(players_count_message, 'ascii'))
            print("Thread ", my_idcount, " looser")
    time.sleep(1)
    cs.close()
    print("Worker Thread ", my_idcount, " end")


def reset_srv():
    global mylock, client_guessed, winner_thread, my_num, threads, e, client_count
    while True:
        e.wait()
        for thread in threads:
            thread.join()
        print("all threads are finished now")
        e.clear()
        mylock.acquire()
        threads = []
        client_guessed = False
        winner_thread = 0
        client_count = 0
        my_num = random.randint(start, stop)
        print('Server number: ', my_num)
        mylock.release()


if __name__ == '__main__':
    try:
        rs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        rs.bind(('0.0.0.0', 1234))
        rs.listen(5)
    except socket.error as msg:
        print(msg.strerror)
        exit(-1)

    t = threading.Thread(target=reset_srv, daemon=True)
    t.start()

    while True:
        client_socket, addrc = rs.accept()
        t = threading.Thread(target=worker, args=(client_socket,))
        threads.append(t)
        client_count += 1
        t.start()

client.py

__author__ = 'emil'

import socket
import struct
import time


if __name__ == '__main__':
    try:
        s = socket.create_connection(('localhost', 1234))
    except socket.error as msg:
        print("Error: ", msg.strerror)
        exit(-1)

    finished = False

    data = s.recv(1024)
    print(data.decode('ascii'))
    step_count = 0
    while not finished:
        my_num = 0

        while True:
            try:
                my_num = int(input("Enter number: "))
                break
            except ValueError:
                print("Invalid input.")

        try:
            s.sendall(struct.pack('!I', my_num))
            answer = s.recv(1)
            message = s.recv(1024)

            if answer == b'S' or answer == b'H':
                print(message.decode('ascii'))
        except socket.error as msg:
            print('Error: ', msg.strerror)
            s.close()
            exit(-2)
        step_count += 1
        print('Sent ', my_num, ' Answer ', answer.decode('ascii'))
        if answer == b'H':
            sr = my_num
        if answer == b'S':
            er = my_num
        if answer == b'G' or answer == b'L':
            finished = True
        time.sleep(0.25)

    s.close()
    if answer == b'G':
        print("You won with", my_num, "in", step_count, "steps")
    else:
        print("You lost. Someone got it right before you!")

You create players_count_message at the first and sent it again and again! Change Your server code to this:

def worker(cs):
    .
    .
    .
    players_count_message = "There are currently %s players in game."

    while not client_guessed:
        try:
            .
            .
            .
            if cnumber > my_num:
                cs.sendall(b'S')
                cs.sendall(bytes(players_count_message %(str(client_count)), 'ascii'))
            if cnumber < my_num:
                cs.sendall(b'H')
                cs.sendall(bytes(players_count_message %(str(client_count)), 'ascii'))

            .
            .
            .

Also, You must check if a players left the game, or connections closed, You must discount that variable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM