[Python] 在 xml.client.ServerProxy 中加入逾時 timeout 機制

[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:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# 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 的效果了:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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 秒就會停止連線:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
# 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 次)

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

這個網站採用 Akismet 服務減少垃圾留言。進一步了解 Akismet 如何處理網站訪客的留言資料