2016-03-15 139 views
0

我一直在Python中使用asyncio.Protocol編寫MUD,但我有一個問題,當用戶關閉他們的客戶端(通常是終端,因爲你通過telnet連接),沒有正確斷開連接。客戶端超時與asyncio.Protocol

服務器不會將用戶識別爲斷開連接,並且它們仍保留在遊戲中。

只有當客戶端連接遠程(出於某種原因,也許有人可以解釋...)時纔會出現問題,從本地主機連接時不會發生此問題。

是否有一個簡潔的方式來檢查用戶是否仍然實際連接(沒有額外的軟件客戶端),或者如果失敗,我該如何合併超時?

我的協議看起來像這樣目前:

class User(Protocol): 

    def connection_made(self, transport): 
     self.transport = transport 
     self.addr = transport.get_extra_info('peername') 
     self.authd = False 
     self.name = None 
     self.admin = False 
     self.room = None 
     self.table = None 
     self.db = None 

     self.flags = [] 

     print("Connected: {}".format(self.addr)) 
     server.connected.append(self) 

     actions['help'](self, ['welcome']) 
     self.get_prompt() 

    def data_received(self, data): 
     msg = data.decode().strip() 
     args = msg.split() 

     if self.authd is False: 
      actions['login'](self, args) 
      return 

     if msg: 
      if args[0] in self.db.aliases: 
       args[0] = str(self.db.aliases[args[0]]) 
       msg = ' '.join(args) 
       args = msg.split() 

      if msg[0] in server.channels: 
       ch = db.session.query(db.models.Channel).get(msg[0]) 
       if msg[1] =='@': 
        channels.send_to_channel(self, ch, msg[2:], do_emote=True) 
       else: 
        channels.send_to_channel(self, ch, msg[1:]) 
       self.get_prompt() 
       return 

      if args[0] in actions: 
       if self.is_frozen(): 
        self.send_to_self("You're frozen solid!") 
       else: 
        actions[args[0]](self, args[1:] if len(args) > 1 else None) 
       self.get_prompt() 
       return 
      self.send_to_self("Huh?") 
     else: 
      if self.table is not None: 
       actions['table'](self, None) 
      elif self.room is not None: 
       actions['look'](self, None) 

    def send_to_self(self, msg): 
     msg = "\r\n" + msg 
     msg = colourify(msg) 
     self.transport.write(msg.encode()) 

    @staticmethod 
    def send_to_user(user, msg): 
     msg = "\r\n"+msg 
     msg = colourify(msg) 
     user.transport.write(msg.encode()) 

    @staticmethod 
    def send_to_users(users, msg): 
     msg = "\r\n"+msg 
     msg = colourify(msg) 
     for user in users: 
      user.transport.write(msg.encode()) 

    def connection_lost(self, ex): 
     print("Disconnected: {}".format(self.addr)) 
     server.connected.remove(self) 

     if self.authd: 
      self.save() 
      server.users.remove(self) 
      self.room.occupants.remove(self) 

注:我已經斬了很多多餘的東西了。如果你想完整的代碼,這是here.

回答

1

您可以調度每data_received()調用一個新的超時處理程序(與先前取消超時處理程序,確定)。我發現這個方法太麻煩了。

或者,作爲選項,切換到asyncio streams - 您可以使用asyncio.wait_for或尚未發佈的全新asyncio.timeout

+0

似乎'asyncio.timeout'被取消 - 請參閱[Async-sig asyncio.timeout()不可移植](https://mail.python.org/pipermail/async-sig/2016-June/000033 .html)和[resurrect asyncio.timeout()上下文管理器·問題#392·python/asyncio](https://github.com/python/asyncio/issues/392) –

+0

'asyncio.timeout'被提取到'async_timeout '圖書館。 它不適用於龍捲風,因爲龍捲風與asyncio不完全兼容(有計劃將其固定在龍捲風5中) –