Python 3(Bot)脚本停止工作

时间:2014-10-21 15:29:42

标签: python multithreading python-3.x

我尝试使用QueryServer连接到TeamSpeak服务器来制作僵尸程序。我已经接受了this thread的建议,但我仍然需要帮助。

我正在使用The TeamSpeak API

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

  1. 它连接。
  2. 检查频道ID(以及它自己的客户端ID)
  3. 它加入频道并开始阅读所有内容
  4. 如果某人说出某个特定命令,它会执行该命令然后断开连接。
  5. 我怎样才能做到它不会断开?如何使脚本保持在等待"在命令执行后它可以继续读取吗?

    我正在使用 Python 3.4.1 我试过学习线程,但要么我愚蠢,要么它没有像我想象的那样工作。还有另一个错误"一旦等待事件,如果我没有用命令触发任何事情,它会在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代码停止的错误只有在manejadorDeEventos触发时才会发生

    编辑1 - 尝试线程化。
    我通过线程搞砸了很长时间,得到了两个客户端同时连接的结果。不知何故,我认为其中一个正在阅读事件而另一个正在回答。脚本不再关闭,这是一场胜利,但克隆连接并不好看。

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

    我想要一个答案,帮助我同时从频道阅读并回答它而不需要为它连接第二个机器人(就像它实际上做的那样......)我会给予额外的如果答案也有助于我理解一个简单的方法,每50秒对服务器进行一次查询,那么它就不会断开连接。

1 个答案:

答案 0 :(得分:1)

the source开始,recv_in_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_in_thread,而不是只召唤一次。

我不确定在哪里通过阅读文档完成此操作,但可能是在收到的事件触发的任何回调结束时;我认为这是你的manejadorDeEventos方法? (或者它可能与servernotifyregister方法有关?我不确定servernotifyregister的用途和on_event是什么......)


manejadorDeEventos提出了两个方面:

  • 您已宣布manejadorDeEventos错误。每个方法都必须将self作为其第一个参数。当您传递绑定方法(如self.manejadorDeEventos)时,绑定self对象将作为第一个参数传递,在调用者传递的任何参数之前。 (对于classmethodstaticmethod,这有例外,但这些不适用于此。)此外,在该方法中,您几乎肯定会访问self,而不是全局变量Bot恰好是与self相同的对象。
  • 如果manejadorDeEventos实际上是recv_in_thread的回调,那么您在此处遇到竞争条件:如果在主线程完成on_event分配之前第一条消息进入,则{ {1}}将无法调用您的事件处理程序。 (这正是那种经常出现一百万次的错误,当你在部署或发布代码几个月后发现它时,调试会非常麻烦。)所以,反过来这两行。

最后一件事:对这个库代码的简要介绍有点令人担忧。它看起来并不是由真正知道自己在做什么的人写的。我上面复制的方法只有3行代码,但它包含一个无用的recv_on_thread和一个永远不会return None的泄漏的Thread,更不用说整个制作设计了在收到的每个事件都很奇怪之后你调用这个方法(并产生一个新的线程),甚至更多,因为它没有真正解释。如果这是您必须使用的服务的标准客户端库,那么您真的没有太多选择,但如果不是,我会考虑寻找不同的库。