2011-11-24 5 views
3

특정 데이터를 전송하기 위해 "배포자"서버에 연결하는 클라이언트를 설정하는 데 문제가 있습니다. 서버의 목적은 클라이언트에서 데이터를 가져온 다음 연결된 모든 클라이언트에 데이터를 보내는 것입니다. 서버는 문제없이 작동합니다. 주 클라이언트는 또한 IRC 봇으로 일하기로되어 있습니다. 다음과 같이 작동하는 텍스트 예제가 있습니다.Python twisted : 함수가 제대로 호출되지 않습니까?

(IRC) John : 안녕하세요!

1. IRC 클라이언트가 메시지를 받았으므로 지금 배포자에게 보내야합니다.

2. 배포자는이 "John : 안녕하세요!" 문자열을 보내고 연결된 모든 클라이언트로 다시 보냅니다. 다른 클라이언트가이 모든 클라이언트에 방송됩니다 유통에 데이터를 보내는 경우는 지정된 채널

에 수신 된 데이터를 차례에

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)입니다 :

(이 하나가 잘 작동하지만 어쩌면 COU LD 내가 "유통"에서 또한 출력 클라이언트가 들어오는 모든 채팅은 "유통"서버에 IRC 서버에서 데이터 및 출력 들어오는 데이터를 원하는

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() 

)를 더 참조하면 유용합니다. 그러나,이 같은 오류를 얻을 :

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에 다음 줄을

, 나는 다음과 같은 오류가

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

같은 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'와는 아무런 관련이 없다고 생각합니다. 그러나이 함수들은 어떻게 든 "통신"하기를 원하지 않기 때문에 "active"가 아닌 다른 서버로 데이터를 보낼 수 있습니다. – Longdouble

답변

4

는이 같은 차단 코드를 작성하지 않도록해야합니다 :

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 인스턴스를 만들고 서로 연결합니다. 이 될 수 있도록하기위한 저장 인스턴스에

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

귀하의 buildProtocol 구현은, 모두가 실종 인스턴스를 생성한다 :

대신 EchoClient().sendData(...), 당신은 당신의 팩토리로 작성된 EchoClient 인스턴스를 사용하려면 IRC 봇이 사용합니다.

이 같은 것을 고려 : 여기주는 특정 코드는 매우 원유 방법입니다

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) 

참고 :

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

귀하의 IRC 클라이언트가 다음 저장 EchoClient 인스턴스를 사용할 수 있습니다. 전역 변수 f을 사용하여 EchoFactory 인스턴스를 찾습니다. 대부분의 전역 변수 사용에서와 같이 코드를 따라 가기가 약간 어렵습니다. 또한 connectionLost 이벤트를 처리하는 코드를 추가하지 않아 connection 특성을 지우지 않았습니다. 즉, 연결이 이미 끊어지면 분산 서버에 데이터를 전송한다고 생각할 수 있습니다. 그리고 비슷하게 IRC 클라이언트가 처음 사용할 때까지 분산 서버에 대한 연결이 생성되었다는 보장이 없기 때문에 f.connection.sendData을 사용하려고 시도 할 때 AttributeError 일 수 있습니다.

그러나 이러한 문제를 해결하는 데는 많은 도약이 필요하지 않습니다.함수에 인수를 전달하고 다른 객체에 참조로 객체를 저장하는 등 전역 변수 사용법을 수정하십시오. AttributeError을 처리하거나 분산 객체를 생성 할 때까지 IRC 연결을 만들지 않음으로써 가능한 한 수정하십시오 연결을 처리하고 속성 값을 None 또는 다른 일부 센티넬로 재설정하여 분실 한 연결을 처리하고 분산 클라이언트 연결을 사용하여 데이터를 보내려고하기 전에 IRC 코드에서 이러한 경우에주의를 기울여야합니다.

+0

고맙습니다! 이제는 모든 것이 분명해졌습니다. 실제로 알아 낸 후에 실제로 작동하게했습니다. – Longdouble

0

TFM은 코드에 정의되어 있지 않으므로 거래가 무엇인지 알 수 없습니다.

다른 오류는 클라이언트를 인스턴스화하지만 reactor.connectTCP(...) 또는 endpoint.connect(...)처럼 절대 연결하지 않는 것입니다. transport 속성은 무언가에 의해 설정 될 때까지 None이됩니다.

(인쇄 된 모든 로그 메시지와 같이 불필요한 세부 정보가 포함되지 않은이 코드의 간단한 버전을 찾는 것이 도움이됩니다. 실제 문제가 무엇인지 알기가 어려워집니다.)

관련 문제