title: How to create bi-directional messaging using AMP in Twisted/Python
body: <p>I'm trying to create a twisted daemon(the server part) that communicates with my local code base (the client part). Basically, the client is supposed to callRemote() using AMP to the daemon to start some processing (updating the database) some methods. After each method is finished processing on the server, I need the server to callRemote() to my client so that the user knows the progress of the server.</p>
  
  <p>I've been able to call to the server from the client and get a response but I can't get the server to send a response to the client.</p>
  
  <p>I've googled for a solution but I can't find any example code that uses AMP for bi-directional communication--it's always the client calling to the server.</p>
  
  <p>I'm trying to get the client to call to the server to start processing (the ServerStart AMP command) and then have the server send multiple calls back to the client to provide updates on processing (the MessageClient AMP command).</p>
  
  <p>Any help would be GREATLY appreciated. A super simple example that shows how to call to the server from the client and then have the server pass back two calls to the client would be awesome!</p>
  
  <p>ampclient.py</p>
  
  <pre><code>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()
  </code></pre>
  
  <p>ampserver.py</p>
  
  <pre><code>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()
  </code></pre>
  
  <p>client_server.py</p>
  
  <pre><code>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)
  </code></pre>