如何使用python SocketServer创建连接超时

时间:2011-08-18 09:46:18

标签: python socketserver

美好的一天!我写的是简单的服务器:

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。对不起我的英语不好。

更新

#!/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 个答案:

答案 0 :(得分:6)

如果你使用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的socket settimeout()调用。

我认为您的alarm()解决方案不适用于线程或分叉。

答案 1 :(得分:3)

请看一下:

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()。