2013-06-25 43 views
0

我有Python的TCP服务器asyncore:asyncore靠近旧插座

class AsyncClientHandler(asyncore.dispatcher_with_send): 
    def __init__(self,sock): 
     asyncore.dispatcher_with_send.__init__(self,sock) 

     self.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 
     self.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) 

     self.message="" 
     self.protocol=Protocol(DBSession, logger) 

    def handle_read(self): 
     data = self.recv(8192) 
     if data: 
      self.message+=data 
      while TERMINATOR in self.message: 
       index=self.message.index(TERMINATOR) 
       msg=self.message[:index] 
       self.message=self.message[index+len(TERMINATOR):] 

       answer=self.protocol.process_msg(msg, DBSession, tarif_dict) 
       if answer: 
        msg = HEADER+answer+TERMINATOR 
        self.send(msg) 

    def handle_close(self): 
     self.close() 

class AsyncServer(asyncore.dispatcher): 
    def __init__(self, host, port): 
     asyncore.dispatcher.__init__(self) 

     self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 

     self.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) 
     self.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) 

     self.set_reuse_addr() 
     self.bind((host, port)) 
     self.listen(5) 

    def handle_accept(self): 
     pair = self.accept() 
     if pair is None: 
      pass 
     else: 
      sock, addr = pair 
      logging.info("Incoming connection from %s",repr(addr)) 
      AsyncClientHandler(sock) 

有些客户端不关闭连接,所以在某些时候服务器崩溃,由于大量的插座。

我怎么能在一段时间后关闭非活动插座? settimeout不起作用。

回答

0

要做到这一点,你可以使用TCP的保持连接(像你已经做了),并设置其延迟,坪......但这apporach应该只用于持久连接,并且仅适用于Unix系统。请阅读here

还可以使插座的一些安排,在经过一段时间关闭它们或推迟他们时,他们是活跃的。我做出了表率与您的代码的工作:

import sched, time 

class SocketSched(threading.Thread): 
    def __init__(self): 
     threading.Thread.__init__(self) 
     self.daemon = True 
     self.to_run = [] 
     self.scheds = {} 
     self.start() 

    def add(self, what): 
     self.to_run.append(what.values()[0]) 
     self.scheds.update(what) 

    def run(self): 
     while True: 
      if self.to_run: 
       run = self.to_run.pop() 
       if not run.empty(): run.run() 
       else: self.to_run.append(run) 

这里我们定义了新的类在不同的线程调度的 - ,sched模块将继续阻止,像asyncore.loop()这是非常重要的。 这需要modificating你的代码位:

class AsyncClientHandler(asyncore.dispatcher_with_send): 
    def __init__(self,sock, sch_class): 
     ... 
     self.delay = 10 
     self.sch_class = sch_class 
     self.sch = sched.scheduler(time.time, time.sleep) 
     self.sch_class.add({self.fileno(): self.sch}) 
     self.event = self.sch_class.scheds[self.fileno()].enter(self.delay, 1, self.handle_close,()) 

    ... 

    def delay_close(self): 
     self.sch_class.scheds[self.fileno()].cancel(self.event) 
     self.event = self.sch_class.scheds[self.fileno()].enter(self.delay, 1, self.handle_close,()) 

    ... 

    def handle_close(self): 
     try: 
      self.sch_class.scheds[self.fileno()].cancel(self.event) 
     except: 
      pass 
     ... 

self.delay是秒的超时。在这段时间过去之后,没有任何行动延迟它,套接字将被关闭。 handle_close()中的行确保它不会因调度程序中的任务而被调用两次。

现在你必须添加self.delay_close()到每一个方法的开头,确保插座是活动的,如。 handle_read()

服务器类(例如获取的SocketSched并将它传递给新的渠道):

class AsyncServer(asyncore.dispatcher): 
    def __init__(self, host, port, sch_class): 
     ... 
     self.sch_class = sch_class 

    ... 

    def handle_accept(self): 
    ... 
      AsyncClientHandler(sock, self.sch_class) 

就绪。使用此方法:

server = AsyncServer('', 1337, SocketSched()) 
asyncore.loop() 

此解决方案可以正常工作,但在某些关闭事件中可能会出现错误。无论如何,当发生超时时,套接字将读取,延迟并关闭。不幸的是运行这样的调度循环使用一些CPU