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

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

问题描述:

我在设置连接到“分销商”服务器以发送特定数据的客户端时遇到了问题。 服务器的目的是从客户端获取数据,然后将该数据发送给所有连接的客户端。服务器没有任何问题。主要客户端也应该作为IRC bot工作。 下面是它应该如何工作的文本示例:Python扭曲:函数调用不正确?

(IRC)John:你好!

1. IRC客户端收到该消息,我们现在需要将其发送给经销商。

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

3.如果其他客户端将数据发送到分配器,其中这将广播到所有的客户端,IRC客户端应输出在它的打开所接收的数据到一指定的通道

下面的代码是IRC僵尸客户端(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):

(这一个工作正常,但也许它凑LD是进一步参考有用)

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在指定的通道中输出?

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

如果我错过了其他任何细节,请告诉我。

谢谢你的时间!

+0

我不知道它是否只是巧合,但在'sendData'中引发第一个错误的行没有正确缩进。 – mac

+0

@mac:我认为它与'sendData'没什么关系,但是这些函数不希望以某种方式相互“通信”,因此它们可以将接收到的数据发送到不同的服务器,而不是“活动”的服务器。 – Longdouble

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

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例如,一个没有连接。 reactor.connectTCP调用会创建一个新连接和一个新的实例并将它们相互关联。

相反的EchoClient().sendData(...),你想用你的工厂创建的EchoClient实例:

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事件以清除connection属性。这意味着当连接丢失时,您可能会认为您正在向分布式服务器发送数据。同样,不能保证在IRC客户端首次尝试使用它时已经创建了到分布式服务器的连接,因此当您尝试使用f.connection.sendData时,您可能有一个AttributeError

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

+0

谢谢!现在一切都很清楚,我确实在弄清楚后才开始工作。 – Longdouble

TFM从未在您的代码中定义,所以我不知道交易是在那里。

另一个错误是您正在实例化一个客户端,但从未将它连接到任何东西,如reactor.connectTCP(...)endpoint.connect(...)transport属性将为None,直到它被设置为止。

(这对您来说是一个很简单的代码,这个代码是完整的,并且不包含所有打印的日志消息等不必要的细节,这对您很有帮助,这让您很难看出真正的问题。 )