首页 文章

即使socket.settimeout为8,Python IRC ChatBot也会在看似随机的时间后挂在socket.recv上

提问于
浏览
1

嘿所以我决定创建一个IRC ChatBot,其唯一目的是从Twitch Chat读取收到的消息,如果赠品被一个关键字识别,它应该通过发送!输入聊天进入赠品 .

我根据这个来源 Build 了Bot:https://github.com/BadNidalee/ChatBot . 我只更改了Run.py中的内容,这是我要发布的唯一代码 . 未经改动的ChatBot确实有效,但它没有重新连接能力,并且由于套接字关闭或其他原因而定期停止接收数据 .

所有我想要改变的是使ChatBot稳定,并且可以在不断开连接的情况下持续留在IRC聊天中 . 我试图通过为我的套接字设置8秒的超时并捕获可能发生的超时异常并在它们发生后重新连接来实现此目的 .

总而言之,它似乎确实有效,我的Bot即使在有大量消息进入时它也应该做到这一点,它会识别赠品何时开始并正确回答 . IRC服务器PING消息也可以正确处理和回答 . 如果Chat中没有消息超过8秒,则异常被正确抛出,Bot也会正确地重新连接到IRC .

继续我的问题:看似随机的时间后,套接字将完全停止工作 . 我觉得奇怪的是它有时会工作20分钟,有时甚至会持续一个小时 . 当聊天中发生特殊事件(如大量消息或其他内容)时,它不会发生,它似乎是随机的 . 它不会超时,不再发生任何事情 . 如果我此时用CTRL-C取消程序控制台sais最后一次调用是“readbuffer = s.recv(1024)”但是为什么它不会在那时抛出超时异常?如果调用了s.recv,那么套接字应该超时,如果在8秒后没有收到任何内容,但是程序只是停止并且在你手动中止它之前没有更多的输出 .

也许我完全错误地走了它 . 我只想要一个稳定的24/7能够ChatBot,它可以扫描一个简单的关键字并用一个简单的答案回答!输入 . 这也是我用Python编写的第一个时间编程,所以如果我违反任何约定或犯了任何严重错误,请告诉我 .

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

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

openSocket方法打开Socket并将JOIN NICK PASS等发送到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

1 回答

  • 0

    我想你已经错过了对socket的超时工作的看法 .

    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)
    

    选择什么是检查缓冲区以查看是否有任何传入数据可用,如果您调用 recv() 本身就是阻塞操作 . 如果缓冲区中没有任何内容 select 将返回空,则应避免调用 recv() .

    如果你're running everything on *Nix you'也最好使用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

相关问题