Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Modify server's variable from client's thread (threading, python)

I implemented a simple network 'game' in Python - server draws a random number, and then the client tries to guess it. My application works great, when the client guesses the number, it disconnects from server (it is handled on client's side).

However, after the proper guess, the number is still the same. I would like to modify the application, such that when the client guesses the number, the server should then rand a new number, so other clients should guess the new one. How can I do this?

Some template, just to draw an attention to the problem:

#!/usr/bin/env python

from random import randint
import socket, select
from time import gmtime, strftime
import threading
import sys

class Handler(threading.Thread):
    def __init__(self, connection, randomnumber):
        threading.Thread.__init__(self)
        self.connection = connection
        self.randomnumber = randomnumber

    def run(self):
        while True:
            try:
                data = self.connection.recv(1024)

                if data:

                    print data

                    try:
                        num = int(data)

                        if Server.guess(num) :
                            msg = "You won! This is the right number!"
                            self.connection.send(msg)
                            break
                        else :
                            msg = "Try again!"
                            self.connection.send(msg)


                    except ValueError, e:
                        msg = "%s" % e
                        self.connection.send(msg)
                else:
                    msg = "error"
                    self.connection.send(msg)

            except socket.error:
                self.connection.close()
                break
        self.connection.close()


class Server:
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.address = (self.ip, self.port)
        self.server_socket = None
        self.randnum = randint(1, 100)


    @classmethod
    def guess(cls, no):
        if cls.randnum == no:
            cls.randnum = randint(1, 1000)
            result = True
        else:
            result = False
        return reslut

    def run(self):
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.bind((self.ip, self.port))
            self.server_socket.listen(10)

            print 'Num is %s' % self.randnum

            while True:
                connection, (ip, port) = self.server_socket.accept()

                c = Handler(connection, self.randnum)
                c.start()

        except socket.error, e:
            if self.server_socket:
                self.server_socket.close()
            sys.exit(1)


if __name__ == '__main__':
    s = Server('127.0.0.1', 1234)
    s.run()
like image 806
yak Avatar asked May 03 '17 10:05

yak


People also ask

What is the use of threading in Python?

A _thread module & threading module is used for multi-threading in python, these modules help in synchronization and provide a lock to a thread in use. A lock has two states, “locked” or “unlocked”. It has two basic methods acquire () and release ().

How to start a new thread in Python?

The function thread.start_new_thread () is used to start a new thread and return its identifier. The first argument is the function to call and its second argument is a tuple containing the positional list of arguments. Let’s study client-server multithreading socket programming by code- Note:-The code works with python3.

What is multithreading in Python?

Multithreading is a process of executing multiple threads simultaneously in a single process. Multi-threading Modules : A _thread module & threading module is used for multi-threading in python, these modules help in synchronization and provide a lock to a thread in use. A lock has two states, “locked” or “unlocked”.

What is ThreadingMixIn in Python socket server?

SocketServer ‘s ThreadingMixIn. The 2nd class out of the above two modules enables the Python server to fork new threads for taking care of every new connection. It also makes the program to run the threads asynchronously. Before we move on to checking the code of the threaded socket server, we suggest you read our previous post.


2 Answers

Generate the random number that is shared between both server and all the client, there should be only instance of this, hence this should be class attribute.
Add a class function guess which return False upon incorrect guess and upon correct guess changes the randnum and returns True

class Server:
    randnum = randint(1, 1000)  # class attribute created

    @classmethod
    def guess(cls, no):        # To be used "guess" if `no` attribute if the same as `cls.randnum`
        if cls.randnum == no:
            cls.randnum = randint(1, 1000)
            result = True
        else:
            result = False
        return result

    def __init__(self, ip, port):
         # ...

The client should call this Server.guess function each time.

like image 54
shanmuga Avatar answered Oct 05 '22 04:10

shanmuga


Actually your issue comes from the fact that you create randnum as an instance method (see your self.randnum) as @shanmuga explained, if you simply declare it as being a class attribute, and remove the instance method it solves your issue (i.e. declaring it in the class directly).

As a side issue (not being an expert on socket), when you send message to the client, you might want to encode them as a byte object (in the run method of Handler, I changed self.connection.send(msg) to self.connection.send(msg.encode())). Also note that I used Python 3.6 (which mainly change the style of print statements)

See the code below:

#!/usr/bin/env python

from random import randint
import socket, select
from time import gmtime, strftime
import threading
import sys

class Handler(threading.Thread):
    def __init__(self, connection, randomnumber):
        threading.Thread.__init__(self)
        self.connection = connection
        self.randomnumber = randomnumber

    def run(self):
        while True:
            try:
                data = self.connection.recv(1024)

                if data:

                    print(data)

                    try:
                        num = int(data)

                        if Server.guess(num) :
                            msg = "You won! This is the right number!"
                            self.connection.send(msg.encode())
                            break
                        else :
                            msg = "Try again!"
                            self.connection.send(msg.encode())


                    except ValueError as e:
                        msg = "%s" % e
                        self.connection.send(msg.encode())
                else:
                    msg = "error"
                    self.connection.send(msg.encode())

            except socket.error:
                self.connection.close()
                break
        self.connection.close()


class Server:
    randnum = randint(1,100)
    def __init__(self, ip, port):
        self.ip = ip
        self.port = port
        self.address = (self.ip, self.port)
        self.server_socket = None


    @classmethod
    def guess(cls, no):
        if cls.randnum == no:
            cls.randnum = randint(1, 1000)
            print("New number is ", cls.randnum )
            result = True
        else:
            result = False
        return result

    def run(self):
        try:
            self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server_socket.bind((self.ip, self.port))
            self.server_socket.listen(10)

            print('Num is %s' % self.randnum)

            while True:
                connection, (ip, port) = self.server_socket.accept()

                c = Handler(connection, self.randnum)
                c.start()

        except socket.error as  e:
            if self.server_socket:
                self.server_socket.close()
            sys.exit(1)


if __name__ == '__main__':
    s = Server('127.0.0.1', 1234)
    s.run()
like image 23
Adonis Avatar answered Oct 05 '22 03:10

Adonis