curious curious - 3 months ago 12
Python Question

Python statefull socket programming

I have a client-server socket python script. I want to keep the state of each connection, such that i identify whether or not the client is its first connection. I unsuccessfully wrote the following code:

`

import socket,sys,SocketServer
from threading import Thread


class EchoRequestHandler(SocketServer.BaseRequestHandler):

def setup(self):
self.clients = {}
print self.client_address, 'connected!'
self.request.send('hi ' + str(self.client_address) + '\n')


def setup(self):
print self.client_address, 'connected!'
self.request.send('hi ' + str(self.client_address) + '\n')

def getFile(self):
fle = self.request.makefile('r')
filename = fle.readline()
print("Got filename {}\n".format(filename))
data = 'fnord' # just something to be there for the first comparison
with open(filename[:-1], 'w') as outfile:
while data:
#data = self.request.recv(1024)
data = fle.read()
#print('writing {!r} to file ....'.format(data))
outfile.write(data)
print("Finish {}\n".format(filename))
print("finish handle")
def handle(self):
addr = self.client_address[0]
print(self.clients)
if addr not in self.clients:
print("firsttime")
self.clients[addr]=1
print(self.clients)
self.getFile()

def finish(self):
print self.client_address, 'disconnected!'
#self.request.send('bye ' + str(self.client_address) + '\n')

class ThreadedTCPServer(SocketServer.ThreadingMixIn,
SocketServer.TCPServer):
pass
if __name__=='__main__':
#server = SocketServer.ThreadingTCPServer(('localhost', 50000), EchoRequestHandler)
server = ThreadedTCPServer(('localhost', 60000), EchoRequestHandler)
server.serve_forever()


Each time the client connect I am getting an empty clients dictionary. Seems like each time there is a connection setup is being called and empties the dictionary
clients
. How i can keep its state at each connection?

Answer

The threaded socket server creates a new instance of EchoRequestHandler for each connection, so storing the clients in that class instance would not be correct.

Each request handler instance has a self.server member that knows its server, so you can store it there instead.

Below is modified from a Python 2.7 SocketServer example in the module's help:

#!python2
import time
import socket
import threading
import SocketServer

class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        self.server.clients.add(self.client_address)
        print 'connected from',self.client_address
        print 'all clients =',self.server.clients
        data = self.request.recv(1024)
        cur_thread = threading.current_thread()
        response = "{}: {}".format(cur_thread.name, data)
        self.request.sendall(response)
        time.sleep(2)
        print 'disconnected'

class ThreadedTCPServer(SocketServer.ThreadingTCPServer):
    def __init__(self,*args,**kwargs):
        SocketServer.ThreadingTCPServer.__init__(self,*args,**kwargs)
        self.clients = set()

def client(ip, port, message):
    sock = socket.socket()
    sock.connect((ip, port))
    try:
        sock.sendall(message)
        response = sock.recv(1024)
        print "Received: {}".format(response)
    finally:
        sock.close()

if __name__ == "__main__":
    # Port 0 means to select an arbitrary unused port
    HOST, PORT = "localhost", 0

    server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
    ip, port = server.server_address

    # Start a thread with the server -- that thread will then start one
    # more thread for each request
    server_thread = threading.Thread(target=server.serve_forever)
    # Exit the server thread when the main thread terminates
    server_thread.daemon = True
    server_thread.start()
    print "Server loop running in thread:", server_thread.name

    client(ip, port, "Hello World 1\n")
    client(ip, port, "Hello World 2\n")
    client(ip, port, "Hello World 3\n")

    server.shutdown()
    server.server_close()

Output:

Server loop running in thread: Thread-1
connected from ('127.0.0.1', 2360)
all clients = set([('127.0.0.1', 2360)])
Received: Thread-2: Hello World 1

connected from ('127.0.0.1', 2361)
all clients = set([('127.0.0.1', 2361), ('127.0.0.1', 2360)])
Received: Thread-3: Hello World 2

connected from ('127.0.0.1', 2362)
all clients = set([('127.0.0.1', 2361), ('127.0.0.1', 2362), ('127.0.0.1', 2360)])
Received: Thread-4: Hello World 3

disconnected
disconnected
disconnected