websocket server

import asyncio
import json
from asyncio import Queue

import websockets

from aw.msg_enum import TOPIC_UDS, KEY_RESP
from aw.aw_upload.blf_upload import RepeatingTimer

from conn.message import Message
from conn.msg_handler import MsgHandler

from func.wcar_log import printi, printe, printd

from data.product_data.socket_msg_log import SocketMsgLogDb


class SocketServer(object):
    PORT = 28657
    CLIENT_UI = 'ui'
    CLIENT_UDS = 'uds'

    def __init__(self):
        self.running = False
        self.topic_hanlder: dict = {}
        self.send_queue = {}
        self.uds_queue = None
        self.loop = None
        self.web_client_dict: dict = {}
        self.web_client_max = 20
        self.status_check_timer = RepeatingTimer(interval=10, function=self.__check_socket_status)

    def start_socket_server(self):
        if self.running:
            printe('SocketServer, socket has already started!')
            return
        self.running = True
        printi('SocketServer, Start socket server')
        self.loop = asyncio.new_event_loop()
        asyncio.set_event_loop(self.loop)
        self.loop.create_task(self.__server())
        self.status_check_timer.start()
        try:
            self.loop.run_forever()
        finally:
            self.loop.close()
            self.loop = None
        printi('SocketServer, Exit socket server loop')

    def stop_socket_server(self):
        printi('SocketServer, ready to stop socket server')
        self.running = False
        self.status_check_timer.cancel()
        tasks = asyncio.all_tasks(loop=self.loop)
        printi('SocketServer, All tasks size: {}'.format(len(tasks)))
        for t in tasks:
            printi('cancel task result: {}'.format(t.cancel()))
        printi('SocketServer, stop asyncio running event loop')
        self.loop.call_soon_threadsafe(self.loop.stop)
        printi('SocketServer, Finished stop event loop')

    def send_msg(self, message):
        if isinstance(message, Message):
            message = json.dumps(message.__dict__)
        printd("Send Socket Message: {}".format(message))
        for hands_ret in self.web_client_dict:
            if self.send_queue[hands_ret].qsize() > 100:
                self.send_queue[hands_ret].get_nowait()
            self.send_queue[hands_ret].put_nowait(message)

    def register_msg_handler(self, topic, handler):
        printi('SocketServer, register_msg_handler, topic: {}, handler: {}'.format(topic, handler))
        self.topic_hanlder.update({topic: handler})

    def is_uds_connected(self):
        return True if self.web_client_dict.get(self.CLIENT_UDS) else False

    async def __server(self):
        self.send_queue = {}
        await websockets.serve(self.__handle_conn, "localhost", SocketServer.PORT)
        printi('SocketServer, Run a server task')

    async def __handle_conn(self, websocket):
        printi('SocketServer, Start handle_conn')
        if len(self.web_client_dict) >= self.web_client_max:
            printi("there has already {len(self.web_client_max)} clients online, please reconnect later.")
            return
        hands_ret = await self.__server_hands(websocket)
        if not hands_ret:
            return
        printi('SocketServer, hand shake success, hands_ret: {}'.format(hands_ret))
        soc_client_data = self.web_client_dict.get(hands_ret)
        if soc_client_data and soc_client_data.tasks:
            for task in soc_client_data.tasks:
                task.cancel()
        await asyncio.sleep(0.1, loop=self.loop)
        printi('SocketServer, All tasks size: {}'.format(len(asyncio.all_tasks(loop=self.loop))))
        if self.CLIENT_UI in hands_ret:
            tasks = [asyncio.create_task(self.__dispatch(websocket)), asyncio.create_task(self.__send(websocket))]
        else:
            self.uds_queue = Queue()
            tasks = [asyncio.create_task(self.__uds_msg_handle(websocket))]
        soc_client_data = SocClientData(websocket, tasks)
        send_queue = Queue(maxsize=500)
        self.web_client_dict.update({hands_ret: soc_client_data})
        self.send_queue.update({hands_ret: send_queue})
        await websocket.send("connection success")
        await asyncio.gather(*tasks)
        # await asyncio.gather(*[self.__dispatch(websocket), self.__send(websocket)])

    async def __server_hands(self, websocket):
        async for msg in websocket:
            printd("SocketServer, recv server_hands msg: {}".format(msg))
            if isinstance(msg, str) and msg.startswith('Hello, I am '):
                printi("SocketServer, Websocket Connected")
                if msg.endswith(self.CLIENT_UI):
                    return (self.CLIENT_UI, websocket.remote_address)
                    #return self.CLIENT_UI
                elif msg.endswith(self.CLIENT_UDS):
                    return self.CLIENT_UDS
            printe('SocketServer, server_hands failed!!')
            return None

    async def __dispatch(self, websocket):
        try:
            async for msg in websocket:
                if msg != 'ping':
                    print('-----msg start --------------------------------')
                    printi(msg)
                    print('-----msg end----------------------------------')
                if msg == 'ping':
                    hands_ret = (self.CLIENT_UI, websocket.remote_address)
                    websocket_client = self.web_client_dict.get(hands_ret)
                    websocket_client.running_status = True
                    await websocket.send('pong')
                else:
                    printi("Get Socket Message: {}".format(msg))
                    message = json.loads(msg, object_hook=Message)
                    topic_handler: MsgHandler = self.topic_hanlder.get(message.topic)
                    if topic_handler:
                        SocketMsgLogDb().fwk_db_write_socket_msg(msg_dict=message.__dict__)
                        topic_handler.handler(message)
                    else:
                        printe('SocketServer, dispatch, can not find handler')
                        topic_handler = self.topic_hanlder.get("DEAULT")
                        topic_handler.handler(message)
        except Exception as e:
            printe("SocketServer, dispatch msg error: {}".format(e))

    async def __send(self, websocket):
        hands_ret = (self.CLIENT_UI, websocket.remote_address)
        while self.running:
            if self.send_queue[hands_ret].empty():
                await asyncio.sleep(0.1, loop=self.loop)
                continue
            msg = self.send_queue[hands_ret].get_nowait()
            try:
                await websocket.send(msg)
            except websockets.ConnectionClosed:
                websocket_client = self.web_client_dict.get(hands_ret)
                websocket_client.running_status = False
                printi(f"client {hands_ret} connection closed.")
            except Exception as ex:
                print(ex)
        printi('SocketServer, send_task, already stop server')

    def __check_socket_status(self):
        """
        定时器返回send_queue 状态
        :return:
        """
        for hands_ret in list(self.web_client_dict.keys()):
            websocket_client = self.web_client_dict.get(hands_ret)
            if not websocket_client.running_status:
                printi(f"remove clent {hands_ret}")
                for task in websocket_client.tasks:
                    task.cancel()
                self.send_queue.pop(hands_ret)
                self.web_client_dict.pop(hands_ret)

    def send_msg_for_uds_key(self, message):
        if isinstance(message, Message):
            message = json.dumps(message.__dict__)
        self.uds_queue.put_nowait(message)

    async def __uds_msg_handle(self, websocket):
        while self.running:
            if self.uds_queue.empty():

                await asyncio.sleep(1, loop=self.loop)
                continue
            msg = self.uds_queue.get_nowait()
            try:
                printi('SocketServer, Start send req msg')
                await websocket.send(msg)
                printi('SocketServer, send req msg finished')
                async for msg in websocket:
                    message = json.loads(msg, object_hook=Message)
                    printi('SocketServer, receive uds msg: {}'.format(msg))
                    if not (message.topic == TOPIC_UDS and message.name == KEY_RESP):
                        printe('SocketServer, wrong msg')
                        continue
                    topic_handler: MsgHandler = self.topic_hanlder.get(message.topic)
                    if topic_handler:
                        topic_handler.handler(message)
                    printi('SocketServer, finished unlock ecu, req_key_ret:')
                    break
            except Exception as e:
                printe("SocketServer, dispatch msg error: {}".format(e))
        printi('SocketServer, send_task, already stop server')


class SocClientData(object):

    def __init__(self, web_soc_client, tasks: list):
        self.web_soc_client = web_soc_client
        self.tasks = tasks
        self.running_status = True
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值