2012-11-23 4 views
7

SocketServer.ThreadingMixin을 사용하는 SimpleXMLRPCServers 체인을 사용할 때 httplib.CannotSendRequest 예외가 간헐적으로 발생합니다.파이썬 : 스레드가있는 SimpleXMLRPCServers를 중첩 할 때 httplib.CannotSendRequest

가 나는 SimpleXMLRPCServer에 함수를 호출 할 XMLRPCLIB를 사용하는 클라이언트 스크립트가 : 나는 '체인'가 무엇을 의미

는 다음과 같습니다. 그 서버는 차례로 다른 SimpleXMLRPCServer를 호출합니다. 그 소리가 얼마나 복잡한 지 알지만,이 아키텍처가 선택되었다는 좋은 이유가 있으며 가능하지 않아야하는 이유는 없습니다. 내가 SocketServer.ThreadingMixin를 사용하지 않는 경우

(testclient)client_script ---calls--> 
    (middleserver)SimpleXMLRPCServer ---calls---> 
     (finalserver)SimpleXMLRPCServer --- does something 
  • 다음이 문제가 발생하지 않습니다 (하지만 난 그렇게 문제가 해결되지 않는 멀티 스레드로 요청을해야합니다.) 난 단지 경우
  • 단일 레벨의 서비스 (예 : 클라이언트 스크립트가 최종 서버를 직접 호출 함)가 발생하지 않습니다.

나는 아래의 간단한 테스트 코드에서 문제를 재현 할 수 있었다. 세 조각이 있습니다

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. 실행 파이썬 finalserver.py
  2. 실행 파이썬 middleserver.py
  3. 실행 파이썬 testclient.py
  4. (3) 여전히 파이썬 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 문제를 해결하는 방향에있는 모든 포인터가 인정 될 것입니다.

    ============================================== ============================================= 답변 :

    좋아, 내가 조금 바보입니다. 나는 너무 오랜 기간 동안 코드를 쳐다 보았다. 나는 명백한 해결책을 찾지 못했다. (대답은 사실 실제 질문에있다.)

    기본적으로 CannotSendRequest가 발생한다. httplib.HTTPConnection이 중간 '요청'작업에 의해 중단되면각 httplib.HTTPConnection.request는 .getresponse() 호출과 쌍을 이루어야합니다. 다른 요청 작업으로 페어링이 중단되면 두 번째 요청에서 CannotSendRequest 오류가 발생합니다. 그래서 : 어떤하는 GetResponse를 호출하기 전에 동일한 연결에서이 개 요청을 가지고 있기 때문에

    connection = httplib.HTTPConnection(...) 
    connection.request(...) 
    connection.request(...) 
    

    이 실패합니다. 이러한 연결이 만들어지고있는 세 가지 프로그램

    1. 유일한 장소가 serverproxy 호출에 내 질문에 그 등을 연결

      .

    2. 문제는 스레딩 중에 만 발생하므로 경쟁 조건이 될 수 있습니다. serverproxy 호출이 공유
    3. 유일한 장소는, 해결책 다음 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 더 없다 연속해서 한 번 이상. 프로그램은 의도 한대로 작동합니다.

    죄송합니다.

  • 답변

    11

    좋아, 나는 좀 어리 석다. 나는 그 대답을 실제로 실제 질문에 쏟아 부어서 내가 뻔한 해결책을 찾지 못한 채 오랜 시간 동안 코드를 보았던 것 같다.

    기본적으로 CannotSendRequest가 발생한다. httplib.HTTPConnection이 중간 '요청'작업에 의해 중단되면 기본적으로 각 httplib.HTTPConnection.request는 .getresponse() 호출과 쌍을 이루어야합니다. 다른 요청 작업으로 페어링이 중단되면 두 번째 요청에서 CannotSendRequest 오류가 발생합니다. 그래서 : 어떤하는 GetResponse를 호출하기 전에 동일한 연결에서이 개 요청을 가지고 있기 때문에

    connection = httplib.HTTPConnection(...) 
    connection.request(...) 
    connection.request(...) 
    

    이 실패합니다. 이러한 연결이 만들어지고있는 세 가지 프로그램

    1. 유일한 장소가 serverproxy 호출에 내 질문에 그 등을 연결

      .

    2. 문제는 스레딩 중에 만 발생하므로 경쟁 조건이 될 수 있습니다. serverproxy 호출이 공유
    3. 유일한 장소는, 해결책 다음 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 번 연속 이상의 위험이 없습니다. 프로그램은 의도 한대로 작동합니다.

    죄송합니다.