![](/img/trans.png)
[英]How do I send commands from PHP script to Terminal running a Python interpreter?
[英]How do I send input from python cmd to autobahn websocket client running in the same interpreter?
我正在嘗試通過 python 的 cmd 庫從交互式提示中獲取輸入,並將輸入傳遞給高速公路 websocket 客戶端以發送到 websocket 服務器。 cmd 循環和高速公路 websocket 客戶端循環在同一個解釋器中運行。 我正在嘗試使用鈎針編織來完成這項工作。 websocket 客戶端成功連接到服務器,但是當我在 cmd 提示符處輸入一些內容以調用 sendMessage 時,我得到了這篇文章底部顯示的異常。 任何關於我可能搞砸的地方的指導將不勝感激。 如果有更好的方法來完成我想做的事情,我會全力以赴。
這些是相關的導入和設置:
from cmd import Cmd
from crochet import setup, run_in_reactor, wait_for, retrieve_result, TimeoutError
# Setup crochet before importing twisted
setup()
from twisted.internet import reactor, ssl
from twisted.python import log
from autobahn.twisted.websocket import WebSocketClientFactory, \
WebSocketClientProtocol, \
connectWS
這是websocket客戶端協議class:
class MyClientProtocol(WebSocketClientProtocol):
def __init__(self, *args, **kwargs):
super(MyClientProtocol, self).__init__(*args, **kwargs)
def onConnect(self, response):
print("Connected")
def onMessage(self, payload, isBinary):
if not isBinary:
print('Message received: {}'.format(payload.decode('utf8')))
def sendTask(self, payload):
payload = json.dumps(payload, ensure_ascii = False).encode('utf8')
self.sendMessage(payload)
這是websocket客戶工廠class:
class MyClientFactory(WebSocketClientFactory):
def __init__(self, *args, **kwargs):
super(MyClientFactory, self).__init__(*args, **kwargs)
def buildFactory(self, uri, headers):
factory = WebSocketClientFactory(uri, headers=headers)
factory.protocol = MyClientProtocol
return factory
這是向 websocket 客戶端發送輸入的 cmd class:
class mycmd(Cmd):
def do_send(self, inp):
payload = {'task': inp}
m = MyClientProtocol()
reactor.callFromThread(m.sendTask, payload)
這就是我調用 websocket 客戶端和 cmd 循環的方式:
if __name__ == '__main__':
@run_in_reactor
def start_connectWS():
headers = {'header1': 'value1'}
f = MyClientFactory()
connectStatement = f.buildFactory(uri, headers)
if connectStatement.isSecure:
contextFactory = ssl.ClientContextFactory()
else:
contextFactory = None
connectWS(connectStatement, contextFactory)
start_connectWS()
mycmd().cmdloop()
這是一個例外:
Unhandled Error
Traceback (most recent call last):
File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/threading.py", line 865, in run
self._target(*self._args, **self._kwargs)
File "/Users/tomd/project/lib/python3.7/site-packages/crochet/_eventloop.py", line 412, in <lambda>
target=lambda: self._reactor.run(installSignalHandlers=False),
File "/Users/tomd/project/lib/python3.7/site-packages/twisted/internet/base.py", line 1283, in run
self.mainLoop()
File "/Users/tomd/project/lib/python3.7/site-packages/twisted/internet/base.py", line 1292, in mainLoop
self.runUntilCurrent()
--- <exception caught here> ---
File "/Users/tomd/project/lib/python3.7/site-packages/twisted/internet/base.py", line 886, in runUntilCurrent
f(*a, **kw)
File "./client.py", line 62, in sendTask
self.sendMessage(payload)
File "/Users/tomd/project/lib/python3.7/site-packages/autobahn/websocket/protocol.py", line 2215, in sendMessage
if self.state != WebSocketProtocol.STATE_OPEN:
builtins.AttributeError: 'MyClientProtocol' object has no attribute 'state'
您的命令 class 創建一個新的未連接協議實例,然后嘗試使用它,就像它已連接一樣:
class mycmd(Cmd):
def do_send(self, inp):
payload = {'task': inp}
m = MyClientProtocol()
reactor.callFromThread(m.sendTask, payload)
具體來說,這會創建您的協議 class 的新實例:
m = MyClientProtocol()
這會嘗試像連接一樣使用它:
reactor.callFromThread(m.sendTask, payload)
稍后,您將擁有將協議實際連接到某些東西的代碼:
connectWS(connectStatement, contextFactory)
但是,此代碼未以任何有用的方式連接到您的命令 class。
您需要使用調用connectWS
產生的連接,而不是創建新的MyClientProtocol
實例。
有很多方法可以讓你權衡取舍。 一種很容易解釋的方法是使用在 websocket 代碼和命令解釋器代碼之間共享的可變 state。
例如, MyClientProtocol.onConnect
可以將自己設置為工廠實例的屬性,您的命令行代碼可以接受工廠實例作為參數,然后從屬性中讀取連接的協議實例。
class MyClientProtocol(...):
def onConnect(self, response):
self.factory.connectedProtocol = self
...
class mycmd(Cmd):
# ... __init__ that accepts factory and sets it on self
def do_send(self, inp):
payload = {'task': inp}
m = self.factory.connectedProtocol
if m is None:
print("No connection")
else:
reactor.callFromThread(m.sendTask, payload)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.