[Python] 在 xml.client.ServerProxy 中加入逾時 timeout 機制
專案從 Python 2 移轉到 Python 3 之後,
原本 IPC 機制裡使用到的 xmlrpc,
加上逾時 timeout 的機制不能用了,得重新在 Python 3 上實作…
上網找了一下,也有人在問 ServerProxy 為什麼不提供 timoeut 參數,
不過大大們的意見是這件事可以交給 Transport 來做,
不需要加在 ServerProxy 上面~
把大大們的範例碼拿來改一下,看起來應該是可以動。
先來做一個實驗的環境~
首先用 nc 跑一個 TCP server 聽在 port 19999,
假裝是一個不會回應的 xmlrpc server:
# nc -l -p 19999
# nc -l -p 19999
# nc -l -p 19999
接著,來看一下我們的 xmlrpc client 要怎麼寫吧~
我寫了一個
IPCClient
IPCClient
的類別,
裡面主要就是使用
xmlrpc.client.ServerProxy
xmlrpc.client.ServerProxy
來發出 XML RPC 的連線。
而逾期 timeout 的部分,則是建立一個
xmlrpc.client.Transport
xmlrpc.client.Transport
物件,
並預先將其內部的
http.client.HTTPConnection
http.client.HTTPConnection
設定 timeout,
然後讓
xmlrpc.client.ServerProxy
xmlrpc.client.ServerProxy
使用這個 xmlrpc.client.Transport
xmlrpc.client.Transport
物件,
這樣就可以在發出連線時,有逾時 timeout 的效果了:
import xmlrpc.client
class IPCClient:
def __init__(self, port, server="127.0.0.1", timeout=5):
# Prepare a transport with timeout
ipc_host = "%s:%d" % (server, port)
transport = xmlrpc.client.Transport()
conn = transport.make_connection(ipc_host)
conn.timeout = timeout
self._proxy = xmlrpc.client.ServerProxy('http://%s' % (ipc_host), transport=transport, allow_none=True)
def call(self, func_name, *func_params):
# Call the function with given parameters
return getattr(self._proxy, func_name)(*func_params)
if __name__ == "__main__":
ipc_client = IPCClient(19999, timeout=3)
print(ipc_client.call("debug"))
import xmlrpc.client
class IPCClient:
def __init__(self, port, server="127.0.0.1", timeout=5):
# Prepare a transport with timeout
ipc_host = "%s:%d" % (server, port)
transport = xmlrpc.client.Transport()
conn = transport.make_connection(ipc_host)
conn.timeout = timeout
self._proxy = xmlrpc.client.ServerProxy('http://%s' % (ipc_host), transport=transport, allow_none=True)
def call(self, func_name, *func_params):
# Call the function with given parameters
return getattr(self._proxy, func_name)(*func_params)
if __name__ == "__main__":
ipc_client = IPCClient(19999, timeout=3)
print(ipc_client.call("debug"))
import xmlrpc.client class IPCClient: def __init__(self, port, server="127.0.0.1", timeout=5): # Prepare a transport with timeout ipc_host = "%s:%d" % (server, port) transport = xmlrpc.client.Transport() conn = transport.make_connection(ipc_host) conn.timeout = timeout self._proxy = xmlrpc.client.ServerProxy('http://%s' % (ipc_host), transport=transport, allow_none=True) def call(self, func_name, *func_params): # Call the function with given parameters return getattr(self._proxy, func_name)(*func_params) if __name__ == "__main__": ipc_client = IPCClient(19999, timeout=3) print(ipc_client.call("debug"))
試著執行上面的程式,確實在 3 秒就會停止連線:
# time python3 ipcclient.py
Traceback (most recent call last):
File "ipcclient.py", line 21, in <module>
print(ipc_client.call("debug"))
File "ipcclient.py", line 16, in call
result = getattr(self._proxy, func_name)(*func_params)
File "/usr/lib64/python3.6/xmlrpc/client.py", line 1112, in __call__
return self.__send(self.__name, args)
File "/usr/lib64/python3.6/xmlrpc/client.py", line 1452, in __request
verbose=self.__verbose
File "/usr/lib64/python3.6/xmlrpc/client.py", line 1154, in request
return self.single_request(host, handler, request_body, verbose)
File "/usr/lib64/python3.6/xmlrpc/client.py", line 1167, in single_request
resp = http_conn.getresponse()
File "/usr/lib64/python3.6/http/client.py", line 1346, in getresponse
response.begin()
File "/usr/lib64/python3.6/http/client.py", line 307, in begin
version, status, reason = self._read_status()
File "/usr/lib64/python3.6/http/client.py", line 268, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "/usr/lib64/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
socket.timeout: timed out
real 0m3.368s
user 0m0.323s
sys 0m0.042s
# time python3 ipcclient.py
Traceback (most recent call last):
File "ipcclient.py", line 21, in <module>
print(ipc_client.call("debug"))
File "ipcclient.py", line 16, in call
result = getattr(self._proxy, func_name)(*func_params)
File "/usr/lib64/python3.6/xmlrpc/client.py", line 1112, in __call__
return self.__send(self.__name, args)
File "/usr/lib64/python3.6/xmlrpc/client.py", line 1452, in __request
verbose=self.__verbose
File "/usr/lib64/python3.6/xmlrpc/client.py", line 1154, in request
return self.single_request(host, handler, request_body, verbose)
File "/usr/lib64/python3.6/xmlrpc/client.py", line 1167, in single_request
resp = http_conn.getresponse()
File "/usr/lib64/python3.6/http/client.py", line 1346, in getresponse
response.begin()
File "/usr/lib64/python3.6/http/client.py", line 307, in begin
version, status, reason = self._read_status()
File "/usr/lib64/python3.6/http/client.py", line 268, in _read_status
line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1")
File "/usr/lib64/python3.6/socket.py", line 586, in readinto
return self._sock.recv_into(b)
socket.timeout: timed out
real 0m3.368s
user 0m0.323s
sys 0m0.042s
# time python3 ipcclient.py Traceback (most recent call last): File "ipcclient.py", line 21, in <module> print(ipc_client.call("debug")) File "ipcclient.py", line 16, in call result = getattr(self._proxy, func_name)(*func_params) File "/usr/lib64/python3.6/xmlrpc/client.py", line 1112, in __call__ return self.__send(self.__name, args) File "/usr/lib64/python3.6/xmlrpc/client.py", line 1452, in __request verbose=self.__verbose File "/usr/lib64/python3.6/xmlrpc/client.py", line 1154, in request return self.single_request(host, handler, request_body, verbose) File "/usr/lib64/python3.6/xmlrpc/client.py", line 1167, in single_request resp = http_conn.getresponse() File "/usr/lib64/python3.6/http/client.py", line 1346, in getresponse response.begin() File "/usr/lib64/python3.6/http/client.py", line 307, in begin version, status, reason = self._read_status() File "/usr/lib64/python3.6/http/client.py", line 268, in _read_status line = str(self.fp.readline(_MAXLINE + 1), "iso-8859-1") File "/usr/lib64/python3.6/socket.py", line 586, in readinto return self._sock.recv_into(b) socket.timeout: timed out real 0m3.368s user 0m0.323s sys 0m0.042s
在外部用 time 指令檢查執行時間,比較不準確,
因為會把程式啟動以及結束的時間都計入,
不過大概還是可以看出程式有依照 timeout 的時間在運作囉~
參考資料:問題 14134: xmlrpc.client.ServerProxy needs timeout parameter
(本頁面已被瀏覽過 504 次)