2012-11-23 5 views
7

SocketServer.ThreadingMixinを使用するSimpleXMLRPCServersのチェーンを使用しているときに、httplib.CannotSendRequest例外を断続的に受信しています。Python:スレッドのSimpleXMLRPCServersをネストするときのhttplib.CannotSendRequest

は私がのSimpleXMLRPCServerの関数を呼び出すためにxmlrpclibを使用するクライアントスクリプトを持っている:私は「連鎖」によって何を意味

は次のとおりです。そのサーバーは次に、別のSimpleXMLRPCServerを呼び出します。私が聞こえることどのように複雑な実現が、このアーキテクチャが選択されていることは良い理由がある、と私はそれが可能であってはならない理由が表示されません。

(testclient)client_script ---calls--> 
    (middleserver)SimpleXMLRPCServer ---calls---> 
     (finalserver)SimpleXMLRPCServer --- does something 
  • 私はSocketServer.ThreadingMixinを使用していない場合、この問題は発生しません(私はこれで解決しないように要求がマルチスレッドにする必要があります。)
  • 私が唯一持っている場合単一のレベルのサービス(つまり、クライアントスクリプトが最終サーバーを直接呼び出している)は発生しません。

私は、以下の簡単なテストコードで問題を再現することができました。 3つのスニペットがあります

finalserver:

import SocketServer 
import time 
from SimpleXMLRPCServer import SimpleXMLRPCServer 
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler 

class AsyncXMLRPCServer(SocketServer.ThreadingMixIn,SimpleXMLRPCServer): pass 

# Create server 
server = AsyncXMLRPCServer(('', 9999), SimpleXMLRPCRequestHandler) 
server.register_introspection_functions() 

def waste_time(): 
    time.sleep(10) 
    return True 

server.register_function(waste_time, 'waste_time') 
server.serve_forever() 

middleserver:

import SocketServer 
from SimpleXMLRPCServer import SimpleXMLRPCServer 
from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler 
import xmlrpclib 

class AsyncXMLRPCServer(SocketServer.ThreadingMixIn,SimpleXMLRPCServer): pass 

# Create server 
server = AsyncXMLRPCServer(('', 8888), SimpleXMLRPCRequestHandler) 
server.register_introspection_functions() 

s = xmlrpclib.ServerProxy('http://localhost:9999') 
def call_waste(): 
    s.waste_time() 
    return True 

server.register_function(call_waste, 'call_waste') 
server.serve_forever() 

testclient:

import xmlrpclib 
s = xmlrpclib.ServerProxy('http://localhost:8888') 
print s.call_waste() 

再現するために、次の手順を使用する必要があります。

  1. 実行Pythonのfinalserver.py
  2. が実行Pythonのmiddleserver.py
  3. 実行Pythonのtestclient.py
  4. (3)は、まだかなりのPython testclient.py

の別のインスタンスを実行し、実行している間頻繁に(ほぼすべての時間)あなたは、あなたがすぐに(4)再びエラーが発生しませんステップを実行しようとした場合、興味深いことに、手順4を実行しようとする最初の時間の下にエラーが発生します。

Traceback (most recent call last): 
    File "testclient.py", line 6, in <module> 
    print s.call_waste() 
    File "/usr/lib64/python2.7/xmlrpclib.py", line 1224, in __call__ 
    return self.__send(self.__name, args) 
    File "/usr/lib64/python2.7/xmlrpclib.py", line 1578, in __request 
    verbose=self.__verbose 
    File "/usr/lib64/python2.7/xmlrpclib.py", line 1264, in request 
    return self.single_request(host, handler, request_body, verbose) 
    File "/usr/lib64/python2.7/xmlrpclib.py", line 1297, in single_request 
    return self.parse_response(response) 
    File "/usr/lib64/python2.7/xmlrpclib.py", line 1473, in parse_response 
    return u.close() 
    File "/usr/lib64/python2.7/xmlrpclib.py", line 793, in close 
    raise Fault(**self._stack[0]) 
xmlrpclib.Fault: <Fault 1: "<class 'httplib.CannotSendRequest'>:"> 

インターネットは、この例外はのGetResponseコールを介在せずにhttplib.HTTPConnection.requestへの複数の呼び出しが原因で発生することができると言うように見えます。しかしながら、インターネットはSimpleXMLRPCServerの文脈でこれを議論しません。 httplib.CannotSendRequestの問題を解決する方向にあるあらゆるポインタが評価されます。

============================================== ============================================= ANSWER:

さて、私は少し愚かです。私は、時間が長すぎてコードを見ていたと思うので、答えが実際の質問に載っているので、顔をして私を見つめている明白な解決策を見逃してしまったと思う。

基本的にCannotSendRequestが発生する介入する「要求」操作によってhttplib.HTTPConnectionが中断されたとき。各httplib.HTTPConnection.requestは、.getresponse()呼び出しとペアにする必要があります。そのペアリングが別の要求操作によって中断された場合、2番目の要求はCannotSendRequestエラーを生成します。 so:getresponseが呼び出される前に同じ接続で2つのリクエストがあるため、失敗します。私の質問にそれをバックリンク

  1. このような接続が行われている三つのプログラムで唯一の場所はServerProxyは呼び出しです。
  2. 問題はスレッド化中にのみ発生するため、競合状態になる可能性があります。 ServerProxyはコールが共有されている唯一の場所がmiddleserver.py

である

  • ソリューション、その後、各スレッドは、それが自分のServerProxyはだ作成させることは明らかです。 middleserverの固定されたバージョンは以下であり、それが機能:独自xmlrpclib.serverproxyを有する各スレッド内のこのバージョンの結果ので

    import SocketServer 
    from SimpleXMLRPCServer import SimpleXMLRPCServer 
    from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler 
    import xmlrpclib 
    
    class AsyncXMLRPCServer(SocketServer.ThreadingMixIn,SimpleXMLRPCServer): pass 
    
    # Create server 
    server = AsyncXMLRPCServer(('', 8888), SimpleXMLRPCRequestHandler) 
    server.register_introspection_functions() 
    
    def call_waste(): 
        # Each call to this function creates its own serverproxy. 
        # If this function is called by concurrent threads, each thread 
        # will safely have its own serverproxy. 
        s = xmlrpclib.ServerProxy('http://localhost:9999') 
        s.waste_time() 
        return True 
    
    server.register_function(call_waste, 'call_waste') 
    server.serve_forever() 
    

    同じインスタンスの危険ServerProxyはのがHTTPConnection.request複数を呼び出すは存在しません連続して1回以上。プログラムは意図したとおりに動作します。

    申し訳ありません。

  • 答えて

    11

    私はちょっとばかです。私は、答えが実際の質問に実際にあるので、顔をして私を見つめている明白な解決策を見逃していた時間を長引かせるためのコードを見ていたと思う。

    基本的にCannotSendRequestが発生する介入する「要求」操作によってhttplib.HTTPConnectionが中断されたとき。基本的には、各httplib.HTTPConnection.requestを.getresponse()呼び出しと組み合わせる必要があります。そのペアリングが別の要求操作によって中断された場合、2番目の要求はCannotSendRequestエラーを生成します。 so:getresponseが呼び出される前に同じ接続で2つのリクエストがあるため、失敗します。私の質問にそれをバックリンク

    1. このような接続が行われている三つのプログラムで唯一の場所はServerProxyは呼び出しです。
    2. 問題はスレッド化中にのみ発生するため、競合状態になる可能性があります。 ServerProxyはコールが共有されている唯一の場所がmiddleserver.py

    である

  • ソリューション、その後、各スレッドは、それが自分のServerProxyはだ作成させることは明らかです。 middleserverの固定バージョンは以下であり、それは動作します:

    独自のxmlrpclib.serverproxyを持つ各スレッドで、このバージョンの結果以来
    import SocketServer 
    from SimpleXMLRPCServer import SimpleXMLRPCServer 
    from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler 
    import xmlrpclib 
    
    class AsyncXMLRPCServer(SocketServer.ThreadingMixIn,SimpleXMLRPCServer): pass 
    
    # Create server 
    server = AsyncXMLRPCServer(('', 8888), SimpleXMLRPCRequestHandler) 
    server.register_introspection_functions() 
    
    def call_waste(): 
        # Each call to this function creates its own serverproxy. 
        # If this function is called by concurrent threads, each thread 
        # will safely have its own serverproxy. 
        s = xmlrpclib.ServerProxy('http://localhost:9999') 
        s.waste_time() 
        return True 
    
    server.register_function(call_waste, 'call_waste') 
    server.serve_forever() 
    

    は、呼び出しServerProxyはHTTPConnection.request一度に連続してより多くの心配はありません。プログラムは意図したとおりに動作します。

    申し訳ありません。

  • 関連する問題