Python:检查 IRC 连接是不是丢失(PING PONG?)

Posted

技术标签:

【中文标题】Python:检查 IRC 连接是不是丢失(PING PONG?)【英文标题】:Python : Check if IRC connection is lost (PING PONG?)Python:检查 IRC 连接是否丢失(PING PONG?) 【发布时间】:2011-07-28 01:05:21 【问题描述】:

所以我的问题是,如果有 PING 并且在一分钟的间隔内没有 ping,我如何让我的机器人听,它会做出反应,就好像连接已经丢失一样。怎么做呢?

编辑:

这是用于注册连接故障的工作代码(尽管在重新连接时遇到了问题):

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import socket
import string
import os
import platform
import time

# Variables
HOST = "irc.channel.net"
PORT = 6667
NICK = "Botname"
IDENT = "Botname"
REALNAME = os.getenv('USER')
CHAN = "##ChannelName"
readbuffer = ""

# Our IRC connection
irc = socket.socket()
irc.settimeout(300)
connected = False
def connection(host, port, nick, ident, realname, chan):
    while connected is False:
        try:
            irc.connect((host, port))
            irc.send("NICK %s\r\n" % nick)
            irc.send("USER %s %s bla :%s\r\n" % (ident, host, realname))
            irc.send("JOIN :%s\r\n" % chan)
            # Initial msg to send when bot connects
            irc.send("PRIVMSG %s :%s\r\n" % (chan, "TehBot: "+ nick + " Realname: " + realname + " ."))
            global connected
            connected = True
        except socket.error:
            print "Attempting to connect..."
            time.sleep(5)
            continue
connection(HOST, PORT, NICK, IDENT, REALNAME, CHAN)

while connected:
    try:
        data = irc.recv ( 4096 )
        # If connection is lost
        if len(data) == 0:
            break
        print data
        # If Nick is in use
        if data.find ( "Nickname is already in use" ) != -1:
            NICK = NICK + str(time.time())
            connection(HOST, PORT, NICK, IDENT, REALNAME, CHAN)
        # Ping Pong so we don't get disconnected
        if data[0:4] == "PING":
            irc.send ( "PONG " + data.split() [ 1 ] + "\r\n" )
    except socket.timeout:
        global connected
        connected = False
        print connected
        break
print "Out of loop"
connection(HOST, PORT, NICK, IDENT, REALNAME, CHAN)

【问题讨论】:

Twisted 是一个可爱的框架。 【参考方案1】:
last_ping = time.time()
threshold = 5 * 60 # five minutes, make this whatever you want
while connected:
    data = irc.recv ( 4096 )
    # If Nick is in use
    if data.find ( 'Nickname is already in use' ) != -1:
        NICK = NICK + str(time.time())
        Connection()
    # Ping Pong so we don't get disconnected
    if data.find ( 'PING' ) != -1:
        irc.send ( 'PONG ' + data.split() [ 1 ] + '\r\n' )
        last_ping = time.time()
    if (time.time() - last_ping) > threshold:
        break

这将记录每次获得 ping 的时间,如果没有 ping 时间过长,则跳出connected 循环。你不需要while connected == True:,只需while connected: 做同样的事情。

另外,请考虑使用connection 而不是Connection,Python 约定仅对类使用大写名称。

【讨论】:

嘿,我一直在尝试实现你的方法,但似乎它并没有继续比较 last_ping 和 time.time()。当连接丢失(不再 PING)时,它不会做任何事情。不知道我做错了什么。你测试过吗?... 我不知道你的意思似乎没有比较两者。更新您的问题或粘贴您的代码并发布链接以便我可以看到它?上面的代码肯定会在五分钟后跳出循环if data.find ( 'PING' ) != -1: 不会发生。尝试更改阈值,尝试添加一些print 语句,告诉我到底发生了什么。 好的,这是我一直在使用的代码的 pastebin 链接以及我得到的输出:pastebin.com/SCumqMiw。发送第二个 PING 后,我终止连接并等待超过 5 分钟,只是为了确定,但没有任何反应(应该打印“连接丢失”)。不知道我是否错过了一些愚蠢的错误,或者我的 python 只是行为不正常:S 感谢到目前为止的帮助 :).. (并试图改变阈值,但结果相同) 1.确保循环下方有一个print 语句,以便知道它是否发生了。 2.irc.recv 会不会屏蔽?如果是这样,一旦连接断开,你就会永远被困在那里,等待你永远不会得到的 4096 字节。如果它被阻塞,你需要设置一个超时。如果这不是问题,我不知道是什么。请注意,您不必同时设置connected = Falsebreak,一个或另一个都可以。 好的,问题是它被阻塞了,所以一旦它失败了,它就不会退出循环。我通过设置 socket.settimeout(300) 来修复它:P...感谢帮助人:)【参考方案2】:

只要您的连接仍然正常,就没有理由做任何花哨的“超时”技巧。如果recv返回的数据长度为0,则TCP连接已经关闭。

data = irc.recv(4096)
if len(data) == 0:
    # connection closed
    pass

我怀疑如果连接没有完全终止,recv() 也会抛出异常。

编辑:

我不确定你想要完成什么。 IRC 服务器偶尔会向您发送PING。如果您没有回复PONG,那么服务器将断开您的连接。当服务器断开您的连接时,您的recv() 调用将返回一个长度为 0 的字符串。

您所要做的就是在收到PING时回复它,并在连接碰巧关闭时进行处理。

你的逻辑应该是这样的:

keep_trying_to_connect = True
while keep_trying_to_connect:
    # try to connect
    irc = socket.socket()
    # send NICK, USER, JOIN here
    # now we're connected and authenticated start your recv() loop
    while True:
        data = irc.recv(4096)
        if len(data) == 0:
            # disconnected, break out of recv loop and try to reconnect
            break
        # otherwise, check what the data was, handling PING, PRIVMSG, etc.

要记住的另一件事是,您需要缓冲任何接收到的数据,直到获得\r\n 序列,您不会总是同时获得一个完整的消息;你可能会得到一半,或三个,或三个半线。

【讨论】:

这不是假设有一个恒定的数据流吗?只有偶尔的 ping,所以不知道它如何知道它应该在什么时候检查这个(试过了但没有用)? 好的,谢谢你的澄清。发现这是因为 socket.setblocking 被设置为阻塞,但是通过设置超时限制来解决这个问题。好的,对 IRC 协议之类的了解不多,但我明白为什么您的示例也可以工作,谢谢 :)【参考方案3】:

您不应使用data.find('PING'),因为它还会在其他消息中找到“PING”。然后你发送了一个错误的 PONG...

改为尝试类似的方法:

if data[0:4] == "PING":
    irc.send("PONG " + data.split()[1] + "\n")

【讨论】:

啊,没想到。谢谢:P 更多pythonic:if data.startswith('PING'): ...【参考方案4】:

您在重新连接时遇到问题的原因是,一旦您这样做了,就没有循环来监听传入的数据,而且您很可能会 ping 超时。连接 while 循环应如下所示:

while connected:
    try:
        ...
    except socket.timeout:
        global connected
        connected = False
        print connected
        connection(HOST, PORT, NICK, IDENT, REALNAME, CHAN)
        continue
print "Out of loop"

现在,当连接超时时,您重新连接并开始监听传入数据。

注意:现在应用程序无法终止它,你必须在命令行中使用 [Ctrl]+[C],或者构造一个“!quit”类型的命令来关闭套接字和应用程序...当然,首先是套接字。

【讨论】:

您好,感谢您对重新连接问题的回复。可能应该更新我的答案以不留下任何松散的结局,但已经使用 try 让它工作了,除了像你建议的那样捕获套接字超时的语句。

以上是关于Python:检查 IRC 连接是不是丢失(PING PONG?)的主要内容,如果未能解决你的问题,请参考以下文章

如何检查连接是不是丢失

如何在 Python 中为 IRC 机器人配置 SSL?

如何在 Perl 中使用 POE::Component::IRC::State 检查用户是不是通过 NickServ 的身份验证?

IRC (rfc1459):哪个事件表明我已连接?

在 Python 中使用 Twitch IRC 时“由对等方重置连接”

Python IRC bot 在 3 次 ping 后断开连接