kakyo
kakyo

Reputation: 11580

Python socketserver stuck at receiving data

I got into a deadlock issue with my simple socketserver/client test. See code

import pickle, json, socket, socketserver, threading
class ServerHandler(socketserver.BaseRequestHandler):
    def __init__(self, request, client_address, server):
        self.message = b''
        socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
    def handle(self):
        while True:
            try:
        # STUCK here when data is fully received.
                data = self.request.recv(1024)
        # STUCK end
                if data is not None:
                    if len(data) > 0:
                        self.message += data
                    else:
                        break
                else:
                    break
            except:
                break
        self.request.send(self.message)

if __name__ == '__main__':
    address = ('localhost', 10000)
    server = socketserver.TCPServer(address, ParameterHandler)
    ip, port = server.server_address

    th = threading.Thread(target=server.serve_forever)
    th.setDaemon(True)
    th.start()

    # Client
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.connect((ip, port))
    s.settimeout(0.2)

    message = pickle.dumps(json.loads(open('test.json').read()))
    lenSent = s.send(message)

    server.shutdown()
    s.close()
    server.socket.close()

From what I can see, my server probably does not know it has received the full data. So the next self.request.recv() call gets stuck. But why isn't it an exception? or why can‘t it simply return None if no valid data is received?

I try to use socketserver to save the trouble of writing a socket server from scratch, but I don't get this module yet.

Upvotes: 1

Views: 1884

Answers (1)

Mark Tolonen
Mark Tolonen

Reputation: 177406

Here's some corrections to round-trip a json message:

import json, socket, socketserver, threading

class ServerHandler(socketserver.BaseRequestHandler):

    # handle should return when the server is done with the connection
    def handle(self):
        message = b''
        while True:
            data = self.request.recv(1024)
            if not data:  # b'' when client shuts down writing on socket.
                break
            message += data
        self.request.sendall(message)  # sendall to ensure sending the full message back.

if __name__ == '__main__':
    address = ('localhost', 10000)
    server = socketserver.TCPServer(address, ServerHandler)
    ip, port = server.server_address

    th = threading.Thread(target=server.serve_forever)
    th.setDaemon(True)
    th.start()

    # Client
    s = socket.socket()
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    s.connect((ip, port))

    # pickle can be exploited to execute code
    message = json.dumps([1,2,3,4]) # returns `str` on Python 3
    lenSent = s.sendall(message.encode()) # encode to `bytes`

    s.shutdown(socket.SHUT_WR) # client has completed sending.

    recvd = b''
    while True:
        data = s.recv(1024)
        if not data: break # b'' when server closes connection.
        recvd += data
    print(json.loads(recvd))
    s.close()

    server.shutdown()
    server.socket.close()

Upvotes: 3

Related Questions