Python3(Bot)脚本停止工作

Python3(Bot)脚本停止工作,python,multithreading,python-3.x,Python,Multithreading,Python 3.x,我正在尝试使用QueryServer连接到TeamSpeak服务器以创建一个机器人。我听取了他的建议,但我仍然需要帮助 这是我正在使用的 在编辑之前,这是我的脚本中实际发生的事情的摘要(1个连接): 它连接 它检查通道ID(以及它自己的客户端ID) 它加入了频道,开始阅读所有内容 如果有人说了一个特定的命令,它会执行该命令,然后断开连接 我怎样才能使它不断开连接?如何使脚本保持“等待”状态,以便在执行命令后继续读取 我正在使用Python 3.4.1 我试着学习线程,但不是我很笨,就是它没有按我

我正在尝试使用QueryServer连接到TeamSpeak服务器以创建一个机器人。我听取了他的建议,但我仍然需要帮助

这是我正在使用的

在编辑之前,这是我的脚本中实际发生的事情的摘要(1个连接):

  • 它连接
  • 它检查通道ID(以及它自己的客户端ID)
  • 它加入了频道,开始阅读所有内容
  • 如果有人说了一个特定的命令,它会执行该命令,然后断开连接
  • 我怎样才能使它不断开连接?如何使脚本保持“等待”状态,以便在执行命令后继续读取

    我正在使用Python 3.4.1
    我试着学习线程,但不是我很笨,就是它没有按我想象的方式工作。还有另一个“bug”,一旦等待事件发生,如果我没有用命令触发任何东西,它会在60秒后断开连接

    #Librerias
    import ts3
    import threading
    import datetime
    from random import choice, sample
    
    # Data needed #
    USER = "thisisafakename"
    PASS = "something"
    HOST = "111.111.111.111"
    PORT = 10011
    SID = 1
    
    
    class BotPrincipal:
        def __init__(self, manejador=False):
            self.ts3conn = ts3.query.TS3Connection(HOST, PORT)
            self.ts3conn.login(client_login_name=USER, client_login_password=PASS)
            self.ts3conn.use(sid=SID)
            channelToJoin = Bot.GettingChannelID("TestingBot")
            try: #Login with a client that is ok
                self.ts3conn.clientupdate(client_nickname="The Reader Bot")
                self.MyData = self.GettingMyData()
                self.MoveUserToChannel(ChannelToJoin, Bot.MyData["client_id"])
                self.suscribirEvento("textchannel", ChannelToJoin)
                self.ts3conn.on_event = self.manejadorDeEventos
                self.ts3conn.recv_in_thread()
            except ts3.query.TS3QueryError: #Name already exists, 2nd client connect with this info
                self.ts3conn.clientupdate(client_nickname="The Writer Bot")
                self.MyData = self.GettingMyData()
                self.MoveUserToChannel(ChannelToJoin, Bot.MyData["client_id"])
    
        def __del__(self):
            self.ts3conn.close()
    
        def GettingMyData(self):
            respuesta = self.ts3conn.whoami()
            return respuesta.parsed[0]
    
        def GettingChannelID(self, nombre):
            respuesta = self.ts3conn.channelfind(pattern=ts3.escape.TS3Escape.unescape(nombre))
            return respuesta.parsed[0]["cid"]
    
        def MoveUserToChannel(self, idCanal, idUsuario, passCanal=None):
            self.ts3conn.clientmove(cid=idCanal, clid=idUsuario, cpw=passCanal)
    
        def suscribirEvento(self, tipoEvento, idCanal):
            self.ts3conn.servernotifyregister(event=tipoEvento, id_=idCanal)
    
        def SendTextToChannel(self, idCanal, mensajito="Error"):
            self.ts3conn.sendtextmessage(targetmode=2, target=idCanal, msg=mensajito) #This works
            print("test") #PROBLEM HERE This doesn't work. Why? the line above did work
    
        def manejadorDeEventos(sender, event):
            message = event.parsed[0]['msg']
            if "test" in message: #This works
                Bot.SendTextToChannel(ChannelToJoin, "This is a test") #This works
    
    
    if __name__ == "__main__":
        Bot = BotPrincipal()
        threadprincipal = threading.Thread(target=Bot.__init__)
        threadprincipal.start()
    
    在使用2个机器人之前,我测试了在SendTextToChannel连接时启动它,它工作正常,允许我在它将文本发送到频道后做任何我想做的事情。使整个python代码停止的bug只有在由manejadorDeEventos触发时才会发生

    编辑1-尝试线程。
    我把线程技术搞得一团糟,结果是两个客户端同时连接。不知何故,我认为其中一个正在阅读事件,另一个正在回答。脚本不再自动关闭,这是一个胜利,但是克隆连接看起来并不好

    编辑2-更新的代码和问题的实际状态。
    我设法让双重连接或多或少“正常”工作,但如果房间里60秒没有任何事情发生,它就会断开连接。尝试使用Threading.timer,但无法使其正常工作。整个问题代码已经更新

    我想要一个答案,帮助我做两个从频道阅读和回答它,而不需要连接第二个机器人为它(就像它实际上正在做…)如果这个答案也能帮助我理解一种简单的方法,每50秒向服务器查询一次,这样它就不会断开连接,那么我会加分。

    从查看来看,
    recv\u-in\u-thread
    不会创建一个循环接收消息的线程,直到退出时间,它创建一个线程,该线程接收单个消息,然后退出:

    def recv_in_thread(self):
        """
        Calls :meth:`recv` in a thread. This is useful,
        if you used ``servernotifyregister`` and you expect to receive events.
        """
        thread = threading.Thread(target=self.recv, args=(True,))
        thread.start()
        return None
    
    这意味着您必须在线程中反复调用
    recv\u
    ,而不是只调用一次

    我不确定从哪里读取文档,但可能是在接收到的事件触发的回调结束时;我想这就是你的
    manejadorDeEventos
    方法?(或者可能与
    servernotifyregister
    方法有关?我不确定
    servernotifyregister
    用于什么,以及
    on_event
    用于什么…)


    manejadorDeEventos
    带来了两个侧重点:

    • 您已声明
      manejadorDeEventos
      错误。每个方法都必须将
      self
      作为其第一个参数。当您传递绑定方法时,如
      self.manejadorDeEventos
      ,绑定的
      self
      对象将作为第一个参数传递,在调用方传递任何参数之前。(对于
      classmethod
      s和
      staticmethod
      s,也有例外情况,但这些情况不适用于此处。)此外,在该方法中,您几乎可以肯定应该访问
      self
      ,而不是碰巧与
      self
      是同一对象的全局变量
      Bot
    • 如果
      manejadorDeEventos
      实际上是
      recv\u in_thread
      的回调,那么这里有一个竞争条件:如果第一条消息在主线程完成
      on_事件
      赋值之前出现,那么
      recv\u on_thread
      将无法调用事件处理程序。(这正是那种经常百万分之一次出现的bug,当你在部署或发布代码几个月后发现它时,调试起来非常痛苦。)所以,把这两行代码颠倒过来


    最后一件事:简单地看一下这个库的代码有点令人担忧。它看起来不像是由真正知道自己在做什么的人写的。我在上面复制的方法只有3行代码,但它包括一个无用的
    返回None
    和一个泄漏的
    线程
    ,它永远不能
    加入
    ,更不用说让你在收到每个事件后调用这个方法(并产生一个新线程)的整个设计是很奇怪的,更重要的是,这并没有得到真正的解释。如果这是你必须使用的服务的标准客户端库,那么在这件事上你真的没有太多选择,但是如果不是,我会考虑寻找一个不同的库。

    @帕克:这是一个更新代码,有一个新问题,而不是一个副本。然而,对OP来说,想办法让这一点更清楚是值得的,因为很多人都会立即做出反应。我不知道该怎么做,特别是当英语不是你的第一语言的时候……也许FAQ有一些指导?作为将来的参考,在本地git存储库中编写这样的代码是值得的,或者至少在对源代码进行重大修改之前备份源文件是值得的。我在项目中也犯过类似的错误,这些错误都会随着备份/源代码管理而消失。我不能再次调用recv_in_线程,因为停止的是python代码,而不是发送到计算机的数据。我强迫它再次调用,错误是“已经收到消息”,正如预期的那样。我不明白为什么整个python代码在SendTextToChannel部分停止,甚至打印函数也停止工作,就像它不是脚本的一部分一样。@Saelyth:好的,这看起来是另一个问题