【问题标题】:Python IRC ChatBot hangs on socket.recv after seemingly random time even though socket.settimeout is 8Python IRC ChatBot 在看似随机的时间后挂在 socket.recv 上,即使 socket.settimeout 是 8
【发布时间】:2016-09-26 01:59:06
【问题描述】:

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

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

我想要改变的只是让 ChatBot 稳定并且可以一直留在 IRC 聊天中而不会断开连接。我试图通过为我的套接字设置 8 秒的超时并捕获可能发生的超时异常并在它们发生后重新连接来实现这一点。

总而言之,它似乎确实有效,即使有很多消息进来,我的 Bot 也会做它应该做的事情,它会识别赠品何时开始并相应地回答。 IRC 服务器 PING 消息也被正确处理和回答。如果聊天中没有消息超过 8 秒,则会正确抛出异常,并且 Bot 也会正确重新连接到 IRC。

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

也许我完全走错了路。我只想要一个稳定的 24/7 全天候聊天机器人,它可以扫描一个简单的关键字并通过一个简单的 !enter 来回答。 这也是我第一次使用 Python 编程,所以如果我违反了任何约定或犯了任何严重错误,请告诉我。

getUser 方法返回当前扫描的聊天行的用户名。

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

openSocket 方法打开 Socket 并向 IRC 发送 JOIN NICK PASS 等

#!/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

【问题讨论】:

    标签: python sockets chat irc receiver


    【解决方案1】:

    我认为您误解了套接字上的超时工作原理。

    s.settimeout(8.0)
    

    只有在无法到达目标主机时才会将s.connect(...) 设置为超时。
    此外,如果s.setblocking(0) 通常你想用什么来代替,但是这本身也不会帮助你(可能)。

    你想要使用的是:

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

    select 所做的是检查缓冲区以查看是否有任何传入数据可用,如果有则调用recv(),这本身就是一个阻塞操作。如果缓冲区中没有任何内容select 将返回空,您应该避免调用recv()

    如果您在 *Nix 上运行所有内容,最好使用 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 的粗略示例。
    但是玩起来很有趣,你应该read more about it

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-14
      • 2012-06-07
      • 2011-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多