簡體   English   中英

Python 3 線程化 websockets 服務器

[英]Python 3 Threaded websockets server

我正在 python 3 中構建一個 Websocket 服務器應用程序。我正在使用這個實現: https ://websockets.readthedocs.io/

基本上我想管理多個客戶。 另外我想從 2 個不同的線程發送數據(一個用於 GPS + 一個用於 IMU)GPS 線程以 1Hz 刷新,而 IMU 線程以 25Hz 刷新

我的問題出在 MSGWorker.sendData 方法中:一旦我取消注釋行 @asyncio.coroutine 並從 websocket.send('{"GPS": "%s"}' % data) 產生,整個方法什么都不做(不打印(“發送數據:foo”)在終端)

但是,通過這兩行注釋,我的代碼可以按預期工作,只是我沒有通過 websocket 發送任何內容。

但是,當然,我的目標是通過 websocket 發送數據,我只是不明白為什么它不起作用? 任何想法 ?

服務器.py

#!/usr/bin/env python3
import signal, sys
sys.path.append('.')
import time
import websockets
import asyncio
import threading

connected = set()
stopFlag = False



class GPSWorker (threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)
    self.data = 0
    self.lastData = 0
    self.inc = 0

  # Simulate GPS data
  def run(self):
    while not stopFlag:
      self.data = self.inc
      self.inc += 1
      time.sleep(1)

  def get(self):
    if self.lastData is not self.data:
      self.lastData = self.data
      return self.data



class IMUWorker (threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)
    self.data = 0
    self.lastData = 0
    self.inc = 0

  # Simulate IMU data
  def run(self):
    while not stopFlag:
      self.data = self.inc
      self.inc += 1
      time.sleep(0.04)

  def get(self):
    if self.lastData is not self.data:
      self.lastData = self.data
      return self.data



class MSGWorker (threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)

  def run(self):
    while not stopFlag:
      data = gpsWorker.get()
      if data:
        self.sendData('{"GPS": "%s"}' % data)          

      data = imuWorker.get()
      if data:
        self.sendData('{"IMU": "%s"}' % data)

      time.sleep(0.04)

  #@asyncio.coroutine
  def sendData(self, data):
    for websocket in connected.copy():
      print("Sending data: %s" % data)
      #yield from websocket.send('{"GPS": "%s"}' % data)



@asyncio.coroutine
def handler(websocket, path):
  global connected
  connected.add(websocket)
  #TODO: handle client disconnection
  # i.e connected.remove(websocket)



if __name__ == "__main__":
  print('aeroPi server')
  gpsWorker = GPSWorker()
  imuWorker = IMUWorker()
  msgWorker = MSGWorker()

  try:
    gpsWorker.start()
    imuWorker.start()
    msgWorker.start()

    start_server = websockets.serve(handler, 'localhost', 7700)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(start_server)
    loop.run_forever()

  except KeyboardInterrupt:
    stopFlag = True
    loop.close()
    print("Exiting program...")

客戶端.html

<!doctype html>
<html>
<head>
  <meta charset="UTF-8" />
</head>
<body>
</body>
</html>
<script type="text/javascript">
  var ws = new WebSocket("ws://localhost:7700", 'json');
  ws.onmessage = function (e) {
    var data = JSON.parse(e.data);
    console.log(data);
  };
</script>

謝謝你的幫助

最后我得到了它 ! 它需要 Python 3.5.1(而我的發行版只提供 3.4.3)和來自 websockets 庫的作者 Aymeric 的一些幫助(感謝他)。

#!/usr/bin/env python3
import signal, sys
sys.path.append('.')
import time
import websockets
import asyncio
import threading


stopFlag = False



class GPSWorker (threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)
    self.data = 0
    self.lastData = 0
    self.inc = 0

  # Simulate GPS data
  def run(self):
    while not stopFlag:
      self.data = self.inc
      self.inc += 1
      time.sleep(1)

  def get(self):
    if self.lastData is not self.data:
      self.lastData = self.data
      return self.data



class IMUWorker (threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)
    self.data = 0
    self.lastData = 0
    self.inc = 0

  # Simulate IMU data
  def run(self):
    while not stopFlag:
      self.data = self.inc
      self.inc += 1
      time.sleep(0.04)

  def get(self):
    if self.lastData is not self.data:
      self.lastData = self.data
      return self.data



class MSGWorker (threading.Thread):
  def __init__(self):
    threading.Thread.__init__(self)
    self.connected = set()

  def run(self):
    while not stopFlag:
      data = gpsWorker.get()
      if data:
        self.sendData('{"GPS": "%s"}' % data)

      data = imuWorker.get()
      if data:
        self.sendData('{"IMU": "%s"}' % data)

      time.sleep(0.04)

  async def handler(self, websocket, path):
    self.connected.add(websocket)
    try:
      await websocket.recv()
    except websockets.exceptions.ConnectionClosed:
      pass
    finally:
      self.connected.remove(websocket)

  def sendData(self, data):
    for websocket in self.connected.copy():
      print("Sending data: %s" % data)
      coro = websocket.send(data)
      future = asyncio.run_coroutine_threadsafe(coro, loop)



if __name__ == "__main__":
  print('aeroPi server')
  gpsWorker = GPSWorker()
  imuWorker = IMUWorker()
  msgWorker = MSGWorker()

  try:
    gpsWorker.start()
    imuWorker.start()
    msgWorker.start()

    ws_server = websockets.serve(msgWorker.handler, '0.0.0.0', 7700)
    loop = asyncio.get_event_loop()
    loop.run_until_complete(ws_server)
    loop.run_forever()
  except KeyboardInterrupt:
    stopFlag = True
    #TODO: close ws server and loop correctely
    print("Exiting program...")

問候,克萊門特

我知道這是一個舊線程,但我正在嘗試模仿該功能,並且我認為有人可能願意伸出援手。

我有兩條 CAN 總線,所以我想要一個線程。 稍后我將有更多線程用於 Web 套接字連接和可能的其他計算任務。

當我在 can0worker 上調用 run 時,代碼卡在了無限的 while 循環中。 我對 python 多線程不夠熟悉,不知道如何修復它。 我認為while循環,因為它在一個單獨的線程上,是非阻塞的,但我的循環阻塞了我所做的測試。

class CANWorker (threading.Thread):
def __init__(self, channel_num):
    threading.Thread.__init__(self)
    self.msg = None
    self.lastmsg = None
    self.channel_num = channel_num
    print("init", self.channel_num)
    os.system(f'sudo ifconfig can{channel_num} down')
    os.system(f'sudo ip link set can{channel_num} up type can bitrate 2000000   dbitrate 8000000 restart-ms 1000 berr-reporting on fd on')
    os.system(f'sudo ifconfig can{channel_num} txqueuelen 65536')
    self.can = can.interface.Bus(channel = f'can{channel_num}', bustype = 'socketcan', fd=True)

def run(self):
    print("run", self.channel_num)
    while not stopFlag:
        self.msg = self.can.recv(0.01)
    
def get(self):
    print("get", self.channel_num)
    if self.lastmsg is not self.msg:
        self.lastmsg = self.msg
        return self.msg

if __name__ == "__main__"中調用它:

can0worker = CANWorker(0)
can1worker = CANWorker(1)
can0worker.run()
can1worker.run()

運行后的結果

init 0

init 1

run 0

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM