2011-08-18 41 views
7

美好的一天!我写了简单的服务器:如何使用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.对不起我的英语不好。

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

回答

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。

+0

这不适合我。我在linux上开始使用服务器作为deamon。我设置server.handle_request(),服务器不回答:/ $ telnet localhost 43 Trying :: 1 ... 尝试127.0.0.1 ... telnet:无法连接到远程主机:连接被拒绝 – user900281

+0

我决定我的在句柄方法中设置警报(5)的问题 – user900281

+0

您无法连接端口43,因为服务器正在监听端口6666.我无法知道您在设置中拥有什么,因为您没有附加这部分代码。 – Adam

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()解决方案将与线程或分叉。