Как создать тайм-аут соединения с Python SocketServer - PullRequest
7 голосов
/ 18 августа 2011

Добрый день! Мне был написан простой сервер:

class SingleTCPHandler(SocketServer.BaseRequestHandler):

    def handle(self):
        data = self.request.recv(1024) 
        self.request.close()

class SimpleServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):

    daemon_threads = True

    allow_reuse_address = True

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


def running():
    server = SimpleServer((settings.host, settings.port), SingleTCPHandler)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        sys.exit(0)

Как установить время ожидания соединения. Я хочу, чтобы когда клиент не отправлял мне данные и не был активен в течение 30 секунд, сервер закрывает соединение.

P.S. Извините за мой английский.

UPDATE

#!/usr/bin/env python
# -*- coding: utf8 -*-

import sys
import time

import SocketServer
import datetime
import settings
import os
from signal import SIGTERM, SIGCHLD, signal, alarm
import socket
import subprocess
from threading import Thread
import MySQLdb
import re

class SingleTCPHandler(SocketServer.BaseRequestHandler):
    "One instance per connection.  Override handle(self) to customize action."
    def handle(self):
        alarm(30)
        data = self.request.recv(1024) 
        # Some code
        self.request.close()


class SimpleServer(SocketServer.ForkingMixIn, SocketServer.TCPServer):

    daemon_threads = True
    allow_reuse_address = True


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




def running():
    server = SimpleServer((settings.host, settings.port), SingleTCPHandler)
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        sys.exit(0)


def deamonize(stdout='/dev/null', stderr=None, stdin='/dev/null', pidfile=None, startmsg='started with pid %s'):
    try:
        pid = os.fork()
        if (pid > 0):
            sys.exit(0)
    except OSError, e:
        sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
        sys.exit(1)

    os.chdir(settings.place)
    os.umask(0)
    os.setsid()

    try:
        pid = os.fork()
        if (pid > 0):
            sys.exit(0) 
    except OSError, e:
        sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
        sys.exit(1)

    if (not stderr):
        stderr = stdout

        print stdin, stdout, stderr
        si = file(stdin, 'r')
        so = file(stdout, 'a+')
        se = file(stderr, 'a+', 0)
        pid = str(os.getpid())
        sys.stderr.write("\n%s\n" % startmsg % pid)
        sys.stderr.flush()
    if pidfile: file(pidfile, 'w+').write("%s\n" % pid)

    os.dup2(si.fileno(), sys.stdin.fileno())
    os.dup2(so.fileno(), sys.stdout.fileno())
    os.dup2(se.fileno(), sys.stderr.fileno())

def startstop(stdout='/dev/null', stderr=None, stdin='/dev/null', pidfile='pid.txt', startmsg='started with pid %s'):
    if len(sys.argv) > 1:
        action = sys.argv[1]
        try:
            pf = open(pidfile)
            pid = int(pf.read().strip())
            pf.close()
        except IOError:
            pid = None
        if ((action == 'stop') or (action == 'restart')):
            if (not pid):
                mess = "Не могу остановить, pid файл '%s' отсутствует.\n"
                sys.stderr.write(mess % pidfile)
                sys.exit(1)
            try:
                while 1:
                    os.kill(pid, SIGTERM)
                    time.sleep(1)
            except OSError, err:
                err = str(err)
                if err.find("No such process") > 0:
                    os.remove(pidfile)
                    if 'stop' == action:
                        sys.exit(0)
                    action = 'start'
                    pid = None
                else:
                    print str(err)
                    sys.exit(1)
        if ('start' == action):
            if (pid):
                mess = "Старт отменен — pid файл '%s' существует.\n"
                sys.stderr.write(mess % pidfile)
                sys.exit(1)
            deamonize(stdout, stderr, stdin, pidfile, startmsg)
            return
    print "Синтакс запуска: %s start|stop|restart" % sys.argv[0]
    sys.exit(2)

if (__name__ == "__main__"):
    startstop(stdout=settings.log, pidfile=settings.pid)
    running()

Ответы [ 2 ]

6 голосов
/ 24 октября 2012

Если вы используете StreamRequestHandler вместо BaseRequestHandler, вам просто нужно переопределить переменную тайм-аута, и она будет установлена. Если вы хотите научиться делать это самостоятельно, просто посмотрите на SocketServer.py

Вот пример, это убьет все соединения, которые не были сделаны в течение 5 секунд:

#!/usr/bin/env python
import SocketServer

class myHandler(SocketServer.StreamRequestHandler):
    timeout = 5
    def handle(self):
        recvdata = ""
        while True:
            tmp = self.request.recv(16384)
            recvdata = recvdata + tmp.strip()
            if (len(tmp) < 16384):
                break;
        self.request.send("Received: {0}".format(recvdata))

class myApp(SocketServer.TCPServer):

    def __init__(self):
        SocketServer.TCPServer.__init__(self, ("localhost", 5555), myHandler)
        print self.server_address
        try:
            self.serve_forever()
        except KeyboardInterrupt:
            print "Got keyboard interrupt, shutting down"
            self.shutdown()

if __name__ == "__main__":
    app = myApp()

Используется вызов python для сокета settimeout () .

Не думаю, что ваше решение alarm() будет работать с многопоточностью или разветвлением.

3 голосов
/ 18 августа 2011

Пожалуйста, посмотрите на это:

import sys
import SocketServer

class SingleTCPHandler(SocketServer.BaseRequestHandler):
    def handle(self):
        data = self.request.recv(1024)
        self.request.close()

class SimpleServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):

    timeout = 30

    daemon_threads = True
    allow_reuse_address = True

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

    def handle_timeout(self):
        print 'Timeout!'


def running():
    server = SimpleServer(('localhost', 6666), SingleTCPHandler)
    try:
        #server.serve_forever()
        server.handle_request()
    except KeyboardInterrupt:
        sys.exit(0)

if __name__ == '__main__':
    running()

# vim: filetype=python syntax=python expandtab shiftwidth=4 softtabstop=4 encoding=utf8

Если вы хотите обработать более одного запроса, вам нужно снова выполнить server.handle_request ().

...