如何在Twisted/Python中使用AMP创建双向消息传递

如何在Twisted/Python中使用AMP创建双向消息传递,python,asynchronous,twisted,Python,Asynchronous,Twisted,我试图创建一个twisted守护进程(服务器部分),它与本地代码库(客户端部分)通信。基本上,客户端应该使用AMP调用remote()来启动一些处理(更新数据库)方法。在服务器上完成每个方法的处理后,我需要服务器向我的客户机调用remote(),以便用户知道服务器的进度 我已经能够从客户端调用服务器并获得响应,但是我无法让服务器向客户端发送响应 我在谷歌上搜索了一个解决方案,但我找不到任何使用AMP进行双向通信的示例代码——总是客户端调用服务器 我试图让客户端调用服务器来开始处理(ServerS

我试图创建一个twisted守护进程(服务器部分),它与本地代码库(客户端部分)通信。基本上,客户端应该使用AMP调用remote()来启动一些处理(更新数据库)方法。在服务器上完成每个方法的处理后,我需要服务器向我的客户机调用remote(),以便用户知道服务器的进度

我已经能够从客户端调用服务器并获得响应,但是我无法让服务器向客户端发送响应

我在谷歌上搜索了一个解决方案,但我找不到任何使用AMP进行双向通信的示例代码——总是客户端调用服务器

我试图让客户端调用服务器来开始处理(ServerStart-AMP命令),然后让服务器将多个调用发送回客户端以提供处理更新(MessageClient-AMP命令)

任何帮助都将不胜感激。一个超级简单的示例演示如何从客户机调用服务器,然后让服务器将两个调用传回客户机,这将非常棒

ampclient.py

from client_server import MessageServer, Client, ServerStart
from twisted.internet.protocol import ClientCreator
from twisted.internet import reactor
from twisted.protocols import amp
from time import sleep
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.application.service import Application
from twisted.application.internet import StreamServerEndpointService

def startServerProcess():
    def show_start(result):
        print 'result from server: %r' % result

    d = ClientCreator(reactor, amp.AMP).connectTCP(
        '127.0.0.1', 1234).addCallback(
            lambda p: p.callRemote(ServerStart, truncate=True)).addCallback(
                show_start)    

pf = Factory()
pf.protocol = Client
reactor.listenTCP(1235, pf)
print 'client listening'

startServerProcess()

sleep(4)

reactor.run()
amserver.py

from client_server import MessageClient, Server
from twisted.internet.protocol import ClientCreator
from twisted.internet import reactor
from twisted.protocols import amp
from time import sleep
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.application.service import Application
from twisted.application.internet import StreamServerEndpointService

def makeClientCall():
    def show_result(result):
        print 'result from client: %r' % result     

    d = ClientCreator(reactor, amp.AMP).connectTCP(
        '127.0.0.1', 1235).addCallback(
            lambda p: p.callRemote(MessageClient)).addCallback(
                show_result)


application = Application("server app")

endpoint = TCP4ServerEndpoint(reactor, 1234)
factory = Factory()
factory.protocol = Server
service = StreamServerEndpointService(endpoint, factory)
service.setServiceParent(application)

sleep(4)

makeClientCall()
makeClientCall()
client_server.py

from twisted.protocols import amp
from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.application.service import Application
from twisted.application.internet import StreamServerEndpointService

class MessageServer(amp.Command):
    response = [('msg', amp.String())]

class ServerStart(amp.Command):
    arguments = [('truncate', amp.Boolean())]
    response = [('msg', amp.String())]

class Server(amp.AMP):
    def message_it(self):
        msg = 'This is a message from the server'
        print 'msg sent to client: %s' % msg
        return {'msg': msg}
    MessageServer.responder(message_it)

    def start_it(self, truncate):
        msg = 'Starting processing...'
        return {'msg': msg}
    ServerStart.responder(start_it)



class MessageClient(amp.Command):
    response = [('msg', amp.String())]

class Client(amp.AMP):
    def message_it(self):
        msg = 'This is a message from the client'
        return {'msg': msg}
    MessageClient.responder(message_it)

下面是一个双向AMP客户端和服务器的简单示例。关键是AMP协议类保存对客户端连接的引用,并提供
callRemote
方法

当然,我只是通过挖掘AMP代码才知道这一点。Twisted文档充其量是缺乏的,至少在核心之外

文件:count\u server.tac

from twisted.protocols.amp import AMP
from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ServerEndpoint
from twisted.application.service import Application
from twisted.application.internet import StreamServerEndpointService

from count_client import Counter

application = Application('test AMP server')

endpoint = TCP4ServerEndpoint(reactor, 8750)
factory = Factory()
factory.protocol = Counter
service = StreamServerEndpointService(endpoint, factory)
service.setServiceParent(application)
文件:count\u client.py

if __name__ == '__main__':
    import count_client
    raise SystemExit(count_client.main())

from sys import stdout

from twisted.python.log import startLogging, err
from twisted.protocols import amp
from twisted.internet import reactor
from twisted.internet.protocol import Factory
from twisted.internet.endpoints import TCP4ClientEndpoint

class Count(amp.Command):
    arguments = [('n', amp.Integer())]
    response = [('ok', amp.Boolean())]

class Counter(amp.AMP):
    @Count.responder
    def count(self, n):
        print 'received:', n
        n += 1

        if n < 10:
            print 'sending:', n
            self.callRemote(Count, n=n)

        return {'ok': True}

def connect():
    endpoint = TCP4ClientEndpoint(reactor, '127.0.0.1', 8750)
    factory = Factory()
    factory.protocol = Counter
    return endpoint.connect(factory)

def main():
    startLogging(stdout)

    d = connect()
    d.addErrback(err, 'connection failed')
    d.addCallback(lambda p: p.callRemote(Count, n=1))
    d.addErrback(err, 'call failed')

    reactor.run()
from twisted.protocols import amp

class Sum(amp.Command):
    arguments = [('a', amp.Integer()),
                 ('b', amp.Integer())]
    response = [('total', amp.Integer())]


class Divide(amp.Command):
    arguments = [('numerator', amp.Integer()),
                 ('denominator', amp.Integer())]
    response = [('result', amp.Float())]
    errors = {ZeroDivisionError: 'ZERO_DIVISION'}


class Math(amp.AMP):
    def sum(self, a, b):
        total = a + b
        print 'Did a sum: %d + %d = %d' % (a, b, total)
        return {'total': total}
    Sum.responder(sum)

    def divide(self, numerator, denominator):
        result = float(numerator) / denominator
        print 'Divided: %d / %d = %f' % (numerator, denominator, result)
        return {'result': result}
    Divide.responder(divide)


def main():
    from twisted.internet import reactor
    from twisted.internet.protocol import Factory
    pf = Factory()
    pf.protocol = Math
    reactor.listenTCP(1234, pf)
    print 'started'
    reactor.run()

if __name__ == '__main__':
    main()
from twisted.internet import reactor, protocol
from twisted.internet.task import deferLater
from twisted.protocols import amp
from ampserver import Sum, Divide


connection = None

class MathClient(amp.AMP):
    def connectionMade(self):
        global connection
        connection = self


class MathFactory(protocol.ReconnectingClientFactory):
    protocol = MathClient


if __name__ == '__main__':
    reactor.connectTCP('127.0.0.1', 1234, MathFactory())
    def simpleSum():
        global connection
        d = connection.callRemote(Sum, a=1, b=5)
        def prin(result):
            print(result)
        d.addCallback(prin)
        return d
    deferLater(reactor, 1, simpleSum)
    deferLater(reactor, 3, simpleSum)
    deferLater(reactor, 6, simpleSum)
    deferLater(reactor, 9, simpleSum)
    deferLater(reactor, 12, simpleSum)
    deferLater(reactor, 15, simpleSum)
    deferLater(reactor, 18, simpleSum).addCallback(lambda _: reactor.stop())
    reactor.run()
如果uuuu name_uuuu=='\uuuuuuu main\uuuuuu':
导入计数\u客户端
引发系统退出(count\u client.main())
从系统导入标准输出
从twisted.python.log导入startLogging,错误
从twisted.amp导入协议
从twisted.internet导入
来自twisted.internet.protocol导入工厂
从twisted.internet.endpoints导入TCP4ClientEndpoint
类计数(amp.命令):
参数=[('n',amp.Integer())]
响应=[('ok',amp.Boolean())]
类计数器(amp.amp):
@计数应答器
def计数(自身,n):
打印“已接收:”,n
n+=1
如果n<10:
打印“发送:”,n
self.callRemote(计数,n=n)
返回{'ok':True}
def connect():
端点=TCP4ClientEndpoint(反应器,'127.0.0.1',8750)
工厂=工厂()
factory.protocol=计数器
返回端点.connect(工厂)
def main():
惊跳(标准动作)
d=连接()
d、 AdderBack(错误,“连接失败”)
d、 addCallback(lambda p:p.callRemote(计数,n=1))
d、 加法器返回(错误,“调用失败”)
反应堆运行()
服务器输出:

$ twistd -n -y count_server.tac
2013-03-27 11:05:18-0500 [-] Log opened.
2013-03-27 11:05:18-0500 [-] twistd 12.2.0 (/usr/bin/python 2.7.3) starting up.
2013-03-27 11:05:18-0500 [-] reactor class: twisted.internet.epollreactor.EPollReactor.
2013-03-27 11:05:18-0500 [-] Factory starting on 8750
2013-03-27 11:05:18-0500 [-] Starting factory <twisted.internet.protocol.Factory instance at 0x2adc368>
2013-03-27 11:05:22-0500 [twisted.internet.protocol.Factory] Counter connection established (HOST:IPv4Address(TCP, '127.0.0.1', 8750) PEER:IPv4Address(TCP, '127.0.0.1', 58195))
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 1
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] sending: 2
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 3
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] sending: 4
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 5
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] sending: 6
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 7
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] sending: 8
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 9
2013-03-27 11:05:26-0500 [Counter,0,127.0.0.1] Counter connection lost (HOST:IPv4Address(TCP, '127.0.0.1', 8750) PEER:IPv4Address(TCP, '127.0.0.1', 58195))
^C2013-03-27 11:05:31-0500 [-] Received SIGINT, shutting down.
2013-03-27 11:05:31-0500 [-] (TCP Port 8750 Closed)
2013-03-27 11:05:31-0500 [-] Stopping factory <twisted.internet.protocol.Factory instance at 0x2adc368>
2013-03-27 11:05:31-0500 [-] Main loop terminated.
2013-03-27 11:05:31-0500 [-] Server Shut Down.
$ python count_client.py
2013-03-27 11:05:22-0500 [-] Log opened.
2013-03-27 11:05:22-0500 [-] Starting factory <twisted.internet.protocol.Factory instance at 0x246bf80>
2013-03-27 11:05:22-0500 [Uninitialized] Counter connection established (HOST:IPv4Address(TCP, '127.0.0.1', 58195) PEER:IPv4Address(TCP, '127.0.0.1', 8750))
2013-03-27 11:05:22-0500 [Counter,client] received: 2
2013-03-27 11:05:22-0500 [Counter,client] sending: 3
2013-03-27 11:05:22-0500 [Counter,client] received: 4
2013-03-27 11:05:22-0500 [Counter,client] sending: 5
2013-03-27 11:05:22-0500 [Counter,client] received: 6
2013-03-27 11:05:22-0500 [Counter,client] sending: 7
2013-03-27 11:05:22-0500 [Counter,client] received: 8
2013-03-27 11:05:22-0500 [Counter,client] sending: 9
^C2013-03-27 11:05:26-0500 [-] Received SIGINT, shutting down.
2013-03-27 11:05:26-0500 [Counter,client] Counter connection lost (HOST:IPv4Address(TCP, '127.0.0.1', 58195) PEER:IPv4Address(TCP, '127.0.0.1', 8750))
2013-03-27 11:05:26-0500 [Counter,client] Stopping factory <twisted.internet.protocol.Factory instance at 0x246bf80>
2013-03-27 11:05:26-0500 [-] Main loop terminated.
$twistd-n-y count\u server.tac
2013-03-27 11:05:18-0500[-]日志已打开。
2013-03-27 11:05:18-0500[-]twistd12.2.0(/usr/bin/python2.7.3)正在启动。
2013-03-27 11:05:18-0500[-]反应器等级:twisted.internet.epollreactor.epollreactor。
2013-03-27 11:05:18-0500[-]工厂从8750开始
2013-03-27 11:05:18-0500[-]启动工厂
2013-03-27 11:05:22-0500[twisted.internet.protocol.Factory]已建立计数器连接(主机:IPv4Address(TCP,'127.0.0.1',8750)对等机:IPv4Address(TCP,'127.0.0.1',58195))
2013-03-27 11:05:22-0500[柜台,0127.0.0.1]收到:1
2013-03-27 11:05:22-0500[计数器,0127.0.0.1]发送:2
2013-03-27 11:05:22-0500[柜台,0127.0.0.1]收到:3
2013-03-27 11:05:22-0500[计数器,0127.0.0.1]发送:4
2013-03-27 11:05:22-0500[柜台,0127.0.0.1]收到:5
2013-03-27 11:05:22-0500[计数器,0127.0.0.1]发送:6
2013-03-27 11:05:22-0500[柜台,0127.0.0.1]收到:7
2013-03-27 11:05:22-0500[计数器,0127.0.0.1]发送:8
2013-03-27 11:05:22-0500[柜台,0127.0.0.1]收到:9
2013-03-27 11:05:26-0500[计数器,0127.0.0.1]计数器连接丢失(主机:IPv4Address(TCP,'127.0.0.1',8750)对等机:IPv4Address(TCP,'127.0.0.1',58195))
^C2013-03-27 11:05:31-0500[-]收到信号,正在关闭。
2013-03-27 11:05:31-0500[-](TCP端口8750关闭)
2013-03-27 11:05:31-0500[-]停止工厂
2013-03-27 11:05:31-0500[-]主回路终止。
2013-03-27 11:05:31-0500[-]服务器关闭。
客户端输出:

$ twistd -n -y count_server.tac
2013-03-27 11:05:18-0500 [-] Log opened.
2013-03-27 11:05:18-0500 [-] twistd 12.2.0 (/usr/bin/python 2.7.3) starting up.
2013-03-27 11:05:18-0500 [-] reactor class: twisted.internet.epollreactor.EPollReactor.
2013-03-27 11:05:18-0500 [-] Factory starting on 8750
2013-03-27 11:05:18-0500 [-] Starting factory <twisted.internet.protocol.Factory instance at 0x2adc368>
2013-03-27 11:05:22-0500 [twisted.internet.protocol.Factory] Counter connection established (HOST:IPv4Address(TCP, '127.0.0.1', 8750) PEER:IPv4Address(TCP, '127.0.0.1', 58195))
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 1
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] sending: 2
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 3
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] sending: 4
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 5
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] sending: 6
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 7
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] sending: 8
2013-03-27 11:05:22-0500 [Counter,0,127.0.0.1] received: 9
2013-03-27 11:05:26-0500 [Counter,0,127.0.0.1] Counter connection lost (HOST:IPv4Address(TCP, '127.0.0.1', 8750) PEER:IPv4Address(TCP, '127.0.0.1', 58195))
^C2013-03-27 11:05:31-0500 [-] Received SIGINT, shutting down.
2013-03-27 11:05:31-0500 [-] (TCP Port 8750 Closed)
2013-03-27 11:05:31-0500 [-] Stopping factory <twisted.internet.protocol.Factory instance at 0x2adc368>
2013-03-27 11:05:31-0500 [-] Main loop terminated.
2013-03-27 11:05:31-0500 [-] Server Shut Down.
$ python count_client.py
2013-03-27 11:05:22-0500 [-] Log opened.
2013-03-27 11:05:22-0500 [-] Starting factory <twisted.internet.protocol.Factory instance at 0x246bf80>
2013-03-27 11:05:22-0500 [Uninitialized] Counter connection established (HOST:IPv4Address(TCP, '127.0.0.1', 58195) PEER:IPv4Address(TCP, '127.0.0.1', 8750))
2013-03-27 11:05:22-0500 [Counter,client] received: 2
2013-03-27 11:05:22-0500 [Counter,client] sending: 3
2013-03-27 11:05:22-0500 [Counter,client] received: 4
2013-03-27 11:05:22-0500 [Counter,client] sending: 5
2013-03-27 11:05:22-0500 [Counter,client] received: 6
2013-03-27 11:05:22-0500 [Counter,client] sending: 7
2013-03-27 11:05:22-0500 [Counter,client] received: 8
2013-03-27 11:05:22-0500 [Counter,client] sending: 9
^C2013-03-27 11:05:26-0500 [-] Received SIGINT, shutting down.
2013-03-27 11:05:26-0500 [Counter,client] Counter connection lost (HOST:IPv4Address(TCP, '127.0.0.1', 58195) PEER:IPv4Address(TCP, '127.0.0.1', 8750))
2013-03-27 11:05:26-0500 [Counter,client] Stopping factory <twisted.internet.protocol.Factory instance at 0x246bf80>
2013-03-27 11:05:26-0500 [-] Main loop terminated.
$python count\u client.py
2013-03-27 11:05:22-0500[-]日志已打开。
2013-03-27 11:05:22-0500[-]启动工厂
2013-03-27 11:05:22-0500[未初始化]已建立计数器连接(主机:IPv4Address(TCP,'127.0.0.1',58195)对等机:IPv4Address(TCP,'127.0.0.1',8750))
2013-03-27 11:05:22-0500[柜台,客户]收到:2
2013-03-27 11:05:22-0500[柜台,客户]发送:3
2013-03-27 11:05:22-0500[柜台,客户]收到:4
2013-03-27 11:05:22-0500[柜台,客户]发送:5
2013-03-27 11:05:22-0500[柜台,客户]收到:6
2013-03-27 11:05:22-0500[柜台,客户]发送:7
2013-03-27 11:05:22-0500[柜台,客户]收到:8
2013-03-27 11:05:22-0500[柜台,客户]发送:9
^C2013-03-27 11:05:26-0500[-]收到信号,正在关闭。
2013-03-27 11:05:26-0500[计数器,客户端]计数器连接丢失(主机:IPv4Address(TCP,'127.0.0.1',58195)对等机:IPv4Address(TCP,'127.0.0.1',8750))
2013-03-27 11:05:26-0500[柜台,客户]停止工厂
2013-03-27 11:05:26-0500[-]主回路终止。

Ryan p之前的回答有些不尽如人意。特别是,它实际上从未使用AMP响应,而是更喜欢在任何地方连锁调用远程调用。以下是我的答案,基于twisted中的ampserver.py(未更改)和ampclient.py(重写)示例。这以一种符合问题的方式回答了关于双向消息传递的基本问题(尽管不是确切的描述)

在简短的摘要中,将回调添加到从callRemote获得的延迟回调,该回调将在其参数中包含响应。这是一本普通字典,你可以用它做你想做的事