Python扭曲:函数调用不正确吗?

我在设置连接到“分发服务器”服务器以发送某些数据的客户端时遇到了问题.
服务器的目的是从客户端获取数据,然后将数据发送到所有连接的客户端.服务器正常运行.
主要客户也应该充当IRC机器人.
这是一个文本示例,说明其工作方式:

(IRC)约翰:你好!

1. IRC客户端收到消息,我们现在需要将其发送给分发者.

2.发行人应该得到这个“约翰:你好!”字符串并将其发送回所有连接的客户端.

3.如果其他客户端将数据发送到分发服务器,并分发给所有客户端,则IRC客户端应在输出时将接收到的数据输出到指定频道

以下代码是IRC bot客户端(ircbot.py):

import sys
import socket
import time
import traceback
from twisted.words.protocols import irc
from twisted.internet import reactor
from twisted.internet import protocol

VERBOSE = True
f = None

class IRCBot(irc.IRCClient):
    def _get_nickname(self):
        return self.factory.nickname
    nickname = property(_get_nickname)

    def signedOn(self):
        self.msg("NickServ", "id <password_removed>") # Identify the bot
        time.sleep(0.1) # Wait a little...
        self.join(self.factory.channel) # Join channel #chantest
        print "Signed on as %s." % (self.nickname,)

    def joined(self, channel):
        print "Joined %s." % (channel,)

    def privmsg(self, user, channel, msg):
        name = user.split('!', 1)[0]
        prefix = "%s: %s" % (name, msg)
        print prefix
        if not user:
            return
        if self.nickname in msg:
            msg = re.compile(self.nickname + "[:,]* ?", re.I).sub('', msg)
            print msg
        else:
            prefix = ''
        if msg.startswith("!"):
            if name.lower() == "longdouble":
                self.msg(channel, "Owner command") # etc just testing stuff
            else:
                self.msg(channel, "Command")
        if channel == "#testchan" and name != "BotName":
            EchoClient().sendData('IRC:'+' '.join(map(str, [name, msg])))
            # This should make the bot send chat data to the distributor server (NOT IRC server)

    def irc_NICK(self, prefix, params):
        """Called when an IRC user changes their nickname."""
        old_nick = prefix.split('!')[0]
        new_nick = params[0]
        self.msg(, "%s is now known as %s" % (old_nick, new_nick))

    def alterCollidedNick(self, nickname):
        return nickname + '1'

class BotFactory(protocol.ClientFactory):
    protocol = IRCBot    
    def __init__(self, channel, nickname='BotName'):
        self.channel = channel
        self.nickname = nickname

    def clientConnectionLost(self, connector, reason):
        print "Lost connection (%s), reconnecting." % (reason,)
        connector.connect()

    def clientConnectionFailed(self, connector, reason):
        print "Could not connect: %s" % (reason,)


class EchoClient(protocol.Protocol):
    def connectionMade(self):
        pass

    def sendData(self, data):
            self.transport.write(data)

    def dataReceived(self, data):
        if VERBOSE:
            print "RECV:", data
        IRC.msg("#chantest", data)
        #This one should send the received data from the distributor to the IRC channel

        def connectionLost(self, reason):
            print "Connection was lost."

class EchoFactory(protocol.ClientFactory):
    def startedConnecting(self, connector):
        print 'Started to connect.'

    def buildProtocol(self, addr):
        print 'Connected to the Distributor'
        return EchoClient()
    def clientConnectionFailed(self, connector, reason):
        print "Cannot connect to distributor! Check all settings!"
        reactor.stop()

    def clientConnectionLost(self, connector, reason):
        print "Distributor Lost connection!!"
        reactor.stop()


if __name__ == "__main__":
    IRC = BotFactory('#chantest')
    reactor.connectTCP('irc.rizon.net', 6667, IRC) # Our IRC connection
    f = EchoFactory()
    reactor.connectTCP("localhost", 8000, f) # Connection to the Distributor server
    reactor.run()

以下代码是分发服务器(distributor.py):

(这可以正常工作,但也许可能对进一步参考很有用)

from twisted.internet.protocol import Protocol, Factory
from twisted.internet import reactor


class MultiEcho(Protocol):
    def __init__(self, factory):
        self.factory = factory

    def connectionMade(self):
        print "Client connected:",self
        self.factory.echoers.append(self)
        self.factory.clients = self.factory.clients+1
        #self.transport.write("Welcome to the server! There are currently "+`self.factory.clients`+" clients connected.")

    def dataReceived(self, data):
        print "RECV:",data
        for echoer in self.factory.echoers:
            echoer.transport.write(data)

    def connectionLost(self, reason):
        print "Client disconnected:",self
        self.factory.echoers.remove(self)
        self.factory.clients = self.factory.clients-1

class MultiEchoFactory(Factory):
    def __init__(self):
        self.clients = 0
        self.names = []
        self.echoers = []

    def buildProtocol(self, addr):
        return MultiEcho(self)

if __name__ == '__main__':
    print "Running..."
    reactor.listenTCP(8000, MultiEchoFactory())
    reactor.run()

我希望客户端将所有传入的聊天数据从IRC服务器输出到“分发服务器”,也希望将输出的数据从“分发服务器”输出.
但是,我得到这样的错误:

对于ircbot.py中的以下行,

EchoClient().sendData('IRC'+' '.join(map(str, [name, msg])))

我收到以下错误:

Joined #chantest.
Longdouble: test
Traceback (most recent call last):
  File "C:\Python\lib\site-packages\twisted\internet\tcp.py", line 460, in doRea
d
    return self.protocol.dataReceived(data)
  File "C:\Python\lib\site-packages\twisted\words\protocols\irc.py", line 2277,
in dataReceived
    basic.LineReceiver.dataReceived(self, data.replace('\r', ''))
  File "C:\Python\lib\site-packages\twisted\protocols\basic.py", line 564, in da
taReceived
    why = self.lineReceived(line)
  File "C:\Python\lib\site-packages\twisted\words\protocols\irc.py", line 2285,
in lineReceived
    self.handleCommand(command, prefix, params)
--- <exception caught here> ---
  File "C:\Python\lib\site-packages\twisted\words\protocols\irc.py", line 2329,
in handleCommand
    method(prefix, params)
  File "C:\Python\lib\site-packages\twisted\words\protocols\irc.py", line 1813,
in irc_PRIVMSG
    self.privmsg(user, channel, message)
  File "C:\Python\Traance\kwlbot\ircbot.py", line 51, in privmsg
    EchoClient().sendData('IRC'+' '.join(map(str, [name, msg])))
  File "C:\Python\Traance\kwlbot\ircbot.py", line 90, in sendData
    self.transport.write(data)
exceptions.AttributeError: 'NoneType' object has no attribute 'write'

相同的ircbot.py中的这一行也是如此

IRC.msg("#chantest", data)

->

RECV: Hello from Distributor Server
Traceback (most recent call last):
  File "C:\Python\Traance\kwlbot\ircbot.py", line 96, in dataReceived
    IRC.msg("#chantest", data)
AttributeError: BotFactory instance has no attribute 'msg'

我究竟做错了什么?如何从IRCbot类中调用正确的函数,以使其将数据发送到分发服务器,以及从分发服务器接收的数据通过IRC在指定的通道中输出?

欢迎任何建议和可能的解决方案.

如果我错过任何其他详细信息,请告诉我.

感谢您的时间!

解决方法:

您应该避免这样编写阻塞代码:

def signedOn(self):
    self.msg("NickServ", "id <password_removed>") # Identify the bot
    time.sleep(0.1) # Wait a little...
    self.join(self.factory.channel) # Join channel #chantest
    print "Signed on as %s." % (self.nickname,)

有关详细信息,请参见Tail -f log on server, process data, then serve to client via twisted.

除此之外,这里的主要问题是您试图在没有连接的情况下发送数据.当您编写类似的内容时:

EchoClient().sendData('IRC'+' '.join(map(str, [name, msg])))

您正在创建一个负责处理连接然后尝试使用它的协议实例,但是您没有在创建连接.尝试发送数据失败,因为该协议尚未附加到任何传输中.

您的代码段已经演示了创建连接的正确方法,实际上是两次:

IRC = BotFactory('#chantest')
reactor.connectTCP('irc.rizon.net', 6667, IRC) # Our IRC connection
f = EchoFactory()
reactor.connectTCP("localhost", 8000, f) # Connection to the Distributor server

错误是创建一个没有连接的新EchoClient实例.反应器.connectTCP调用创建一个新的连接和一个新的EchoClient实例,并将它们彼此关联.

您要使用工厂创建的EchoClient实例,而不是EchoClient().sendData(…):

def buildProtocol(self, addr):
    print 'Connected to the Distributor'
    return EchoClient()

您的buildProtocol实现创建了实例,所需要的只是保存实例,以便IRC机器人可以使用它.

考虑这样的事情:

def buildProtocol(self, addr):
    print 'Connected to the Distributor'
    self.connection = EchoClient()
    return self.connection

然后,您的IRC客户端可以使用保存的EchoClient实例:

    if channel == "#testchan" and name != "BotName":
        f.connection.sendData('IRC:'+' '.join(map(str, [name, msg])))
        # This should make the bot send chat data to the distributor server (NOT IRC server)

请注意,我在这里给出的特定代码是一种非常粗糙的方法.它使用全局变量f查找EchoFactory实例.与大多数全局变量用法一样,这会使代码难以遵循.此外,我还没有添加任何代码来处理connectionLost事件以清除连接属性.这意味着您可能会认为当连接已经丢失时,您正在将数据发送到分布式服务器.同样,不能保证在IRC客户端第一次尝试使用它时就已经建立了与分布式服务器的连接,因此在尝试使用f.connection.sendData时可能会出现AttributeError.

但是,解决这些问题并不需要很大的飞跃.像其他任何方法一样,修复全局变量的用法-通过将参数传递给函数,将对象另存为其他对象上的引用等.通过处理可能的AttributeError或直到创建分布式对象之后才创建IRC连接来修复可能的AttributeError.通过将属性值重置为None或其他一些标记来处理丢失的连接,并在尝试使用分布式客户端连接发送任何数据之前注意IRC代码中的这种情况.

上一篇:python-使用扭曲检查IRC通道中的用户是否“发声”或“ op”


下一篇:恶意代码安全攻防