Python IRC ChatBot在看似随机的时间后挂在socket.recv上,即使socket.settimeout为8 [英] Python IRC ChatBot hangs on socket.recv after seemingly random time even though socket.settimeout is 8

查看:102
本文介绍了Python IRC ChatBot在看似随机的时间后挂在socket.recv上,即使socket.settimeout为8的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

嘿,所以我决定创建一个IRC ChatBot,其唯一目的是读取来自Twitch聊天的传入消息,如果赠品被关键字识别,则应该通过在聊天中发送!enter来进入赠品。

Hey so I decided to create an IRC ChatBot whose sole purpose it is to read incoming messages from Twitch Chat and if a giveaway is recognized by a keyword it's supposed to enter the giveaway by sending !enter in Chat.

我在此源上构建Bot: https://github.com/ BadNidalee / ChatBot 。我只更改了Run.py中的内容,因此这是我要发布的唯一代码。不变的ChatBot确实可以工作,但是它没有重新连接功能,并且由于套接字关闭或其他原因而定期停止接收数据。

I build the Bot upon this source: https://github.com/BadNidalee/ChatBot. I only changed things in the Run.py so thats the only Code I'm going to post. The unaltered ChatBot does work but it has no reconnect ability and regularly stops receiving data because the socket closes or other reasons.

我想要更改的只是使它保持稳定,并且可以不断开连接就一直保持在IRC聊天中。我试图通过为套接字设置8秒钟的超时并捕获可能发生的超时异常并在它们发生后重新连接来实现此目的。

All I wanted to change was make it so that the ChatBot is stable and can just stay in the IRC Chat constantly without disconnecting. I tried to achieve this by setting a timeout of 8 seconds for my socket and catching timeout exceptions that would occur and reconnect after they occur.

为了工作,即使有很多消息进入,我的机器人也照做了它应该做的事情,它识别赠品何时开始并相应地回答。 IRC Server PING消息也得到正确处理和答复。如果在聊天中超过8秒钟没有消息,则正确抛出该异常,并且漫游器也正确地重新连接到IRC。

And all in all it does seem to work, my Bot does what it's supposed to even when alot of messages are coming in, it recognizes when a Giveaway starts and answers acordingly. IRC Server PING Messages are also handled and answered correctly. If there is no message in Chat for over 8 seconds the Exception gets thrown correctly and the Bot also reconnects correctly to IRC.

这是我的问题:在看似随机的时间之后,套接字实际上会停止工作。我发现奇怪的是,它有时会工作20分钟,有时甚至是一个小时。当特殊事件(例如大量消息或聊天中发生的其他事件)不会发生时,它似乎确实是随机的。它不会超时,什么也不会发生。如果此时我用CTRL-C取消了程序,控制台会说最后一次调用是 readbuffer = s.recv(1024),但是为什么它此时不抛出超时异常呢?如果调用s.recv,则套接字应超时,如果8秒后仍未收到任何消息,但该程序只是停止并且没有更多输出,直到您手动中止它为止。

BUT heres my Problem: After seemingly random times the socket will literally just Stop working. What I find strange is it will sometimes work for 20 minutes and sometimes for an hour. It doesn't occur when special events, like lots of messages or something else happens in Chat, it really seems random. It will not timeout there's just nothing happening anymore. If I cancel the program with CTRL-C at this point the console sais the last call was "readbuffer = s.recv(1024)" But why is it not throwing a timeout exception at that point? If s.recv was called the socket should timeout if nothing is received after 8 seconds but the program just stops and there is no more output until you manually abort it.

也许我完全以错误的方式去做。我只想要一个稳定的24/7可用的ChatBot,它可以扫描一个简单的关键字并用一个简单的!enter回答。
这也是我第一次使用Python编程,因此如果我违反任何约定或遇到任何严重错误,请通知我。

Maybe I went about it the wrong way completely. I just want a stable 24/7-able ChatBot that scans for one simple keyword and answers with one simple !enter. This is also my first Time programming in Python so If I broke any conventions or made any grave mistakes let me know.

getUser方法返回用户名

The getUser Method returns the username of the line of chat that is scanned currently.

getMessage方法返回已扫描的聊天行的消息。

The getMessage Method returns the message of the line of chat that is scanned.

openSocket方法打开套接字并将JOIN NICK PASS等发送到IRC

The openSocket Method opens the Socket and sends JOIN NICK PASS etc to the IRC

#!/usr/bin/python
import string
import socket
import datetime
import time
from Read import getUser, getMessage
from Socket import openSocket, sendMessage
from Initialize import joinRoom

connected = False
readbuffer = ""


def connect():
    print "Establishing Connection..."
    irc = openSocket()
    joinRoom(irc)
    global connected
    connected = True
    irc.settimeout(8.0)
    print "Connection Established!"
    return irc

while True:
    s = connect()
    s.settimeout(8.0)
    while connected:
            try:
                readbuffer = s.recv(1024)
                temp = string.split(readbuffer, "\n")
                readbuffer = temp.pop()


                for line in temp:
                    if "PING" in line:
                        s.send(line.replace("PING", "PONG"))
                        timern = str(datetime.datetime.now().time())
                        timern = timern[0:8]
                        print timern + " PING received"
                        break

                    user = getUser(line)
                    message = getMessage(line)
                    timern = str(datetime.datetime.now().time())
                    timern = timern[0:8]
                    print timern +" " + user + ": " + message
                    if "*** NEW" in message:
                        sendMessage(s, "!enter")
                        break


            except socket.timeout:
                connected = False
                print "Socket Timed Out, Connection closed!"
                break
            except socket.error:
                connected = False
                print "Socket Error, Connection closed!"
                break


推荐答案

我认为您误会了

s.settimeout(8.0)

如果无法到达目的地,只会将 s.connect(...)设置为超时主机。

更进一步,通常是 s.setblocking(0)您想使用的东西,但是单单这也无法帮助您(可能)。

Will only set s.connect(...) to timeout if it can't reach the destination host.
Further more, usually what you want to use instead if s.setblocking(0) however this alone won't help you either (probably).

相反,您要使用的是:

import select
ready = select.select([s], [], [], timeout_in_seconds)
if ready[0]:
    data = s.recv(1024)

选择执行的操作是检查缓冲区以查看是否有可用的传入数据,如果有,请调用 recv()本身是一项阻止操作。如果缓冲区中没有任何内容,则 select 将返回空,并且应避免调用 recv()

What select does is check the buffer to see if any incoming data is available, if there is you call recv() which in itself is a blocking operation. If there's nothing in the buffer select will return empty and you should avoid calling recv().

如果您正在* Nix上运行所有内容,最好也使用 epoll

If you're running everything on *Nix you're also better off using epoll.

from select import epoll, EPOLLIN
poll = epoll()
poll.register(s.fileno(), EPOLLIN)

events = poll.poll(1) # 1 sec timeout
for fileno, event in events:
    if event is EPOLLIN and fileno == s.fileno():
        data = s.recv(1024)

这是如何使用epoll的粗略示例。

但是玩起来很有趣,您应该详细了解

This is a crude example of how epoll could be used.
But it's quite fun to play around with and you should read more about it

这篇关于Python IRC ChatBot在看似随机的时间后挂在socket.recv上,即使socket.settimeout为8的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆