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()
재현하려면 다음 단계를 사용해야합니다
- 실행 파이썬 finalserver.py
- 실행 파이썬 middleserver.py
- 실행 파이썬 testclient.py (3) 여전히 파이썬 testclient.py의 다른 인스턴스를
확실히 실행 실행
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(...)
이 실패합니다. 이러한 연결이 만들어지고있는 세 가지 프로그램
- 유일한 장소가 serverproxy 호출에 내 질문에 그 등을 연결
.
- 문제는 스레딩 중에 만 발생하므로 경쟁 조건이 될 수 있습니다. 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 더 없다 연속해서 한 번 이상. 프로그램은 의도 한대로 작동합니다.
죄송합니다.