2

私はXML-RPCサーバーを持っています:

import time

import xmlrpclib
from SimpleXMLRPCServer import SimpleXMLRPCServer

class Worker(object):
    def start_work(self):
        # is it possible do return value to client here?
        self.do_work()
        return 'we started!'

    def do_work(self):
        while(True):
            print 'I\'m doing work...'
            time.sleep(3)


if __name__ == '__main__':
    port = 8080
    server = SimpleXMLRPCServer(("localhost", port))
    print "Listening on port %s..." % port

    w = Worker()

    server.register_function(w.start_work)
    while(1):
        server.handle_request()

# vim: filetype=python syntax=python expandtab shiftwidth=4 softtabstop=4 encoding=utf8

そして簡単なクライアント:

import xmlrpclib
c = xmlrpclib.ServerProxy('http://localhost:8080/')
print c.start_work()

もちろん、start_work関数によって返される値が出力されることはありません。

私の質問は、作業を終了する前に戻り値を可能にするためにサーバーコードを書き直す方法です。そのためにスレッドを使用できることは知っていますが、もっと簡単な方法がないことを確認したいと思います。

4

2 に答える 2

4

長時間実行され、早期に返されるタスクを備えたXML-RPCが必要な場合は、サーバーをツイストなどの非同期フレームワークに書き直す必要があります。

于 2011-08-18T16:56:11.147 に答える
1

スレッドなしで、またはSimpleXMLRPCServerの一部を再実装せずに、またはXMLRPCプロトコルを壊さずに、このようなことを行うのが良い考えかどうかはわかりませんがyield、呼び出されたメソッドでステートメントを使用することで、早期の回答を得ることができます。

class Worker(object):
    def start_work(self):
        # is it possible do return value to client here?
        # yes, with a yield
        yield "the_return_value"
        self.do_work()
        # but yielding a first value and returning it to client will disable any next response
        # return 'we started!'

    def do_work(self):
        while(True):
            print 'I\'m doing work...'
            time.sleep(3)

そして、のdo_POSTメソッドをオーバーライドして、呼び出されたメソッドをSimpleXMLRPCRequestHandler2回呼び出します(###部分の周りはすべてPythonコードの標準部分です)

class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):

    def do_POST(self):
        """Handles the HTTP POST request.
        Attempts to interpret all HTTP POST requests as XML-RPC calls,
        which are forwarded to the server's _dispatch method for handling.
        """
        # Check that the path is legal
        if not self.is_rpc_path_valid():
            self.report_404()
            return

        try:
            # Get arguments by reading body of request.
            # We read this in chunks to avoid straining
            # socket.read(); around the 10 or 15Mb mark, some platforms
            # begin to have problems (bug #792570).
            max_chunk_size = 10*1024*1024
            size_remaining = int(self.headers["content-length"])
            L = []
            while size_remaining:
                chunk_size = min(size_remaining, max_chunk_size)
                L.append(self.rfile.read(chunk_size))
                size_remaining -= len(L[-1])
            data = ''.join(L)

            # In previous versions of SimpleXMLRPCServer, _dispatch
            # could be overridden in this class, instead of in
            # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
            # check to see if a subclass implements _dispatch and dispatch
            # using that method if present.
            response = self.server._marshaled_dispatch(
                    data, getattr(self, '_dispatch', None)
                )
            ##############################################
            ##############################################
            ## Here you'll have the first part of your response
            response = response.next() # to get the first item of the generator (yes, a little bit uggly)
            ##############################################
            ##############################################
        except Exception, e: # This should only happen if the module is buggy
            # internal error, report as HTTP server error
            self.send_response(500)

            # Send information about the exception if requested
            if hasattr(self.server, '_send_traceback_header') and \
                    self.server._send_traceback_header:
                self.send_header("X-exception", str(e))
                self.send_header("X-traceback", traceback.format_exc())

            self.end_headers()
        else:
            # got a valid XML RPC response
            self.send_response(200)
            self.send_header("Content-type", "text/xml")
            self.send_header("Content-length", str(len(response)))
            self.end_headers()
            self.wfile.write(response)

            # shut down the connection
            self.wfile.flush()
            self.connection.shutdown(1)

            ##############################################
            ##############################################
            ## Here you've send the the first part of your response to the client, relaunch the method
            self.server._marshaled_dispatch(
                    data, getattr(self, '_dispatch', None)
            )
            ##############################################
            ##############################################

次に、メインは次のようになります:

if __name__ == '__main__':
    port = 8080
    server = SimpleXMLRPCServer(("localhost", port), requestHandler=MySimpleXMLRPCRequestHandler)
    print "Listening on port %s..." % port

    w = Worker()

    server.register_function(w.start_work)
    while(1):
        server.handle_request()
于 2011-08-18T15:04:39.293 に答える