Python: проверьте, не потеряно ли соединение IRC (PING PONG?) - PullRequest
1 голос
/ 28 июля 2011

Итак, мой вопрос, как мне заставить моего бота слушать, если есть 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)

Ответы [ 4 ]

5 голосов
/ 28 июля 2011
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

Это будет записывать время каждый раз, когда он получает пинг, и если он будет слишком длинным без него, выйдет из цикла connected. Вам не нужно while connected == True:, просто while connected: делает то же самое.

Кроме того, рассмотрите возможность использования connection вместо Connection, в Python принято использовать заглавные имена только для классов.

3 голосов
/ 28 июля 2011

Нет причин делать какие-либо хитрые трюки с тайм-аутом, пока ваше соединение все еще работает. Если длина данных, возвращаемых из recv, равна 0, соединение TCP было закрыто.

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

Я подозреваю, что recv () также может выдать исключение, если соединение не было завершено без ошибок.

Edit:

Я не уверен, чего вы пытаетесь достичь. 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, вы не всегда будете получать ровно одно законченное сообщение одновременно; Вы можете получить половину одной, или трех, или трех с половиной строк.

2 голосов
/ 28 июля 2011

Не следует использовать data.find('PING'), поскольку он также находит «PING» в других сообщениях.И тогда вы отправляете неправильный PONG ...

Вместо этого попробуйте что-то вроде этого:

0 голосов
/ 22 сентября 2011

Причина, по которой у вас возникли проблемы с повторным подключением, заключается в том, что, как только вы это сделаете, у вас не будет цикла для прослушивания входящих данных, и вы, скорее всего, будете проверять время ожидания.Цикл while connection должен выглядеть следующим образом:

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", чтобы сначала закрыть сокет и сокет приложения ... сокета, конечно.

...