【问题标题】:How to create connection timeout with python SocketServer如何使用 python SocketServer 创建连接超时
【发布时间】:2011-10-29 15:28:26
【问题描述】:

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

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 秒内不活动时,服务器将关闭连接。

附:对不起我的英语不好。

更新

#!/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()

【问题讨论】:

    标签: python socketserver


    【解决方案1】:

    如果你使用 StreamRequestHandler 而不是 BaseRequestHandler,你只需要覆盖那里的 timeout 变量,它就会被设置。如果您想自己学习如何做,只需查看 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() 解决方案不适用于线程或分叉。

    【讨论】:

      【解决方案2】:

      请看:

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

      【讨论】:

      • 这对我不起作用。我将服务器作为 linux 中的守护进程启动。我设置了 server.handle_request() ,服务器没有应答:/$ telnet localhost 43 Trying ::1... Trying 127.0.0.1... telnet:无法连接到远程主机:连接被拒绝
      • 我决定我的问题是在handle方法中设置警报(5)
      • 您无法在端口 43 上连接,因为服务器正在侦听端口 6666。我不知道您在设置中有什么,因为您没有附加这部分代码。
      • 不,服务器监听 43 端口。我不是复制你的列表代码,我只复制 server.handle_request、handle_timeout 函数、超时 = 30 和我的守护进程启动和停止。 Wen 我在运行功能中添加了 while 1 。服务器是答案,但这不是我想要的,因为我无法停止连接。警报已停止为我连接。
      • 请在此处更新您的问题和代码。我不确定它现在的样子。
      猜你喜欢
      • 1970-01-01
      • 2019-03-11
      • 1970-01-01
      • 2015-08-11
      • 2016-03-15
      • 2019-06-30
      • 2017-04-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多