arnm
arnm

Reputation: 1765

Python socket hangs program

I am working on a simple HTTP server in Python. I am taking bits and pieces from here: http://hg.python.org/cpython/file/3.3/Lib/socketserver.py to see how Python's standard library handles it.

My problem is that as soon as I try to accept requests my program hangs. Here is my code its only 100 lines so I'll just post it directly here.

I have a process() function which is in a loop that loops forever and it's suppose to handle new connections. Inside I have a print statement that only gets printed once.

print('processing') in TCPServer.process()

I have tried threading off process() but I get the same result.

"""."""

import socket
import select
from abc import abstractmethod, ABCMeta


class BaseServer(metaclass=ABCMeta):

    def __init__(self, server_address, server_port, RequestHandlerClass):
        self._server_address = server_address
        self._server_port = server_port
        self._RequestHandlerClass = RequestHandlerClass
        self._running = False

    def serve_forever(self):
        self._running = True
        while self._running:
            self.process()

    @abstractmethod
    def process(self):
        pass

    def shutdown(self):
        self._running = False


class TCPServer(BaseServer):

    def __init__(self,
                server_address,
                server_port,
                RequestHandlerClass,
                address_family=socket.AF_INET,
                socket_type=socket.SOCK_STREAM,
                request_queue_size=1,
                bind=True):

        super(TCPServer, self).__init__(server_address,
                                        server_port,
                                        RequestHandlerClass)

        self._address_family = address_family
        self._socket_type = socket_type
        self._request_queue_size = request_queue_size
        self._socket = socket.socket(self._address_family, self._socket_type)
        self._read_list = [self._socket]

        if bind:
            self.bind()

    def bind(self):
        self._socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self._socket.bind((self._server_address, self._server_port))
        self._socket.listen(self._request_queue_size)

    def shutdown(self):
        super().shutdown()
        self._socket.close()

    def process(self):
        print('processing')
        readable, writeable, errored = select.select(self._read_list, [], [])
        for socket in readable:
            if socket is self._socket:
                client_socket, client_address = self._socket.accept()
                self._read_list.append(client_socket)
                print('connection from: ', client_address)
            else:
                self._RequestHandlerClass(client_socket)
                self._read_list.remove(client_socket)


class BaseRequestHandler(metaclass=ABCMeta):

    def __init__(self, client_socket):
        self._client_socket = client_socket

        self.setup()
        try:
            self.handle()
        finally:
            self.finish()

    @abstractmethod
    def setup(self):
        pass

    @abstractmethod
    def handle(self):
        pass

    @abstractmethod
    def finish(self):
        pass


class HTTPRequestHandler(BaseRequestHandler):

    def setup(self):
        print('REQUEST SETUP')
        print(self._client_socket.recv(2048))

    def handle(self):
        print('REQUEST HANDLE')

    def finish(self):
        print('REQUEST FINISH')
        self._client_socket.close()


if __name__ == '__main__':
    tcp_server = TCPServer(server_address='',
                        server_port=9000,
                        RequestHandlerClass=HTTPRequestHandler)
    tcp_server.serve_forever()

Upvotes: 0

Views: 1253

Answers (1)

Greg Hewgill
Greg Hewgill

Reputation: 992707

I ran your code but couldn't make it hang. However, there is a fatal error in your process() function where you refer to client_socket in the else: branch, but client_socket is not defined at that point. You probably meant to refer to socket.

I was able to make two connections to the server on port 9000, and get "connection from:" lines for each. As soon as one of those connections sent something, your server would crash for the above reason.

Upvotes: 3

Related Questions