2011-08-18 61 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()解決方案將與線程或分叉。