Pergunta

I'm implementing a simple server which should print a message if nothing is received for 3 seconds.

Handler

class SingleTCPHandler(SocketServer.StreamRequestHandler):
    def handle(self):
        while True:
            message = self.rfile.readline().strip()
            print message

Server

class SimpleServer(SocketServer.TCPServer):
    timeout = 3

    def handle_timeout(self):
        print "Timeout"

    def __init__(self, server_address, RequestHandlerClass):
        SocketServer.TCPServer.__init__(self, server_address, RequestHandlerClass)

Here I'm extending the TCPServer for testing the timeout method. I've set the timeout atribute to 3. According to the docs, if that time passes and no messages are sent to the client handle_timeout() is called which, in my case, just prints 'Timeout'.

BaseServer.timeout

Timeout duration, measured in seconds, or None if no timeout is desired. If handle_request() receives no incoming requests within the timeout period, the handle_timeout() method is called.

I start the server, and observe it's output. When i connect to it and send some messages, they are normally printed. However, if I don't send anything for 3 seconds or more, nothing happens. As if the timeout and handle_timeout() haven't been implemented.

What could be the source of this behavior?

Foi útil?

Solução 4

In the end, I dropped the socketserver module and went directly with socket module, in which timeout worked.

TIMEOUT = 3
HOST = '192.0.0.202'              
PORT = 2000             

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind((HOST, PORT))
s.listen(1)

while 1:
    conn, addr = s.accept()
    conn.settimeout(TIMEOUT)
    while 1:
        try:
            data = conn.recv(1024)
            #Do things

        except socket.timeout:
            #Timeout occurred, do things

        if not data or P=='end':
            print 'Connection lost. Listening for a new controller.' 
            break

conn.close()

Outras dicas

you must not call server_forever() method for app loop. try this one instead:

while True:
  self.handle_request()

handle_timeout() works for me then.

Can you try declare the timeout at self.timeout (i.e make it a instance field instead of class variable ?)

EDIT (here is the code)

def handle_request(self):
           """Handle one request, possibly blocking.

          Respects self.timeout.
          """
          # Support people who used socket.settimeout() to escape
          # handle_request before self.timeout was available.
          timeout = self.socket.gettimeout()
          if timeout is None:
               timeout = self.timeout
           elif self.timeout is not None:
               timeout = min(timeout, self.timeout)
           fd_sets = select.select([self], [], [], timeout)
           if not fd_sets[0]:
               self.handle_timeout()
               return
           self._handle_request_noblock()

Here is the document of serve_forever():

Handle requests until an explicit shutdown() request. Poll for shutdown every poll_interval seconds. Ignores self.timeout. If you need to do periodic tasks, do them in another thread

So the serve_forever() will only check if shutdown() is called every poll_interval whose default value is 0.5 seconds. And only handle_request() care about the timeout.

Here is the code for serve_forever() and handle_request().

First of all, what do you mean by "[the server] should print a message if nothing is received for 3 seconds."?

Do you mean that the server should ...

  1. shutdown if it hadn't any new requests in certain period?
  2. close a connection if it isn't finished in a certain period?

In the first case you can use BaseServer.timeout but you would also have to use BaseServer.handle_request() instead of BaseServer.server_forever().

In the second case you should have set the timeout for the SingleTCPHandler:

class SingleTCPHandler(SocketServer.StreamRequestHandler):
    timeout = 3
    def handle(self):
        while True:
            message = self.rfile.readline().strip()
            print message

For people who want to use their own implementation of BaseRequestHandler:

class MyRequestHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        self.request.settimeout(3)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top