websockets.exceptions.ConnectionClosedOK错误解决方案

websockets.exceptions.ConnectionClosedOK错误原因及解决方案

针对python中websockets出现 sent 1000 (OK); then received 1000 (OK)错误的解决方案;

Traceback (most recent call last):
  File "d:\test\websocket\Tclients.py", line 42, in startup
    recv_text = await websocket.recv()
  File "C:\Program Files\Python39\lib\site-packages\websockets\legacy\protocol.py", line 552, in recv
    await self.ensure_open()
  File "C:\Program Files\Python39\lib\site-packages\websockets\legacy\protocol.py", line 920, in ensure_open  
    raise self.connection_closed_exc()
websockets.exceptions.ConnectionClosedOK: sent 1000 (OK); then received 1000 (OK)

错误产生的原因

在python挖掘websocket数据时,比较完善的包文件是websockets文件,只需要

pip install websockets
然后在正文中引用即可完成
import websockets

完整使用代码一般如下:

import asyncio
import websockets
import logging
from datetime import datetime
import json
import traceback
import pymysql     # For find ipadress for ping
#当前存在的主要问题是各个线程、协程存在冲突,导致最后死锁。
def functionToDB(mes):
    dbconnect = pymysql.connect(host="localhost", user="root", password="root", database="****",charset="utf8")
    updateSQL= ("INSERT INTO keyvalue (`keys`,`starts`,`types`,`lens`) "
        "VALUES(%(keys)s,%(starts)s,%(types)s,%(lens)s)")
    start=mes.split(':')[0]
    start=start[2:].replace('"','')
    dic_json = json.loads(mes)
    cursor = dbconnect.cursor()
    if isinstance(dic_json,dict): #判断是否是字典类型isinstance 返回True false
        for key in dic_json:
            add_mes = {
                'keys': key,
                'starts': start,
                'types': str(type(dic_json[key])),
                'lens': len(str(dic_json[key])),
            }   
            try:
                cursor.execute(updateSQL,add_mes)
                dbconnect.commit()
            except Exception as e:
                print("更新失败!")
                traceback.print_exc()
                print(e.with_traceback)
sendstr = '{"SESSION_ID":"-1101623267","SESSION_NAME":"*****","HOST_IP":"*.*.*.*","USER_ID":"********","USER_NAME":"****","FILTER_ID":[*********],"msg_type":1}'
#存在问题在第1000个数据包时会报错:received 1000 (OK); then sent 1000 (OK)
async def startup(uri):
    async with websockets.connect(uri) as websocket:
        await websocket.send(sendstr)
        logging.info("< Hello world!")
        while True:
            try:
                recv_text = await websocket.recv()
                print(">:",recv_text)
                #ping pong 流程  根据服务器不同,流程不同
                if recv_text[0:13] =='{"msg":"ping"':
                    print("<:",recv_text)
                    await websocket.send(recv_text)
                functionToDB(recv_text)
            except Exception as e:
                traceback.print_exc()
                
if __name__ == '__main__':
        #websocket的地址     
        remote = 'ws://*.*.*.*:80/webSocket'
        loop=asyncio.get_event_loop()
        loop.run_until_complete(startup(remote))
    except KeyboardInterrupt as exc:
        logging.info('Quit.')

以上程序中存在的问题就是websocket.recv()中数据流量及速度以服务器为主,如果服务器发送信息流量速度快于insertDB()处理数据的速度,就会出现以上错误。因错误内容显示过于模糊,很多人无法一次性定位问题原因,导致无法使用。

解决办法

运用多线程及消息队列技术,将websocket.recv()接收的数据存入消息队列,将处理数据的比较慢的function从消息队列中获得数据,避免了快等慢的问题,可以非常完美的解决该问题。

import asyncio
import logging
from datetime import datetime
from aiowebsocket.converses import AioWebSocket
import pymysql     # For find ipadress for ping
import json
import traceback
#这个处理程序存在问题:将过长的frame没有进行拼接直接返回。
header="""
GET /auth/getcurrentuser HTTP/1.1
Host: *.*.*.*:8080
Connection: keep-alive
Accept: application/json
combine-token: 50b78947-9b7f-4d94-a242-e1e87dd89b66,de4751ef-ab3d-4127-8a15-1c228405d99d
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.61 Safari/537.36
Content-Type: application/json;charset=UTF-8
Referer: http://*.*.*.*:8080/ams/view/ams_alarm_custom_view/54
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: ''; ''=''
"""
#这个函数是插入key的函数不太完善
def insertSQL(mes,dbconnect):
    addSQL= ("INSERT ignore INTO kayvalues (`keys`,`starts`,`cnts`) VALUES(%(keys)s,%(starts)s,0)")
    start=mes.decode('utf8').split(':')[0]
    start=start[2:].replace('"','')
    dic_json = json.loads(mes)
    cursor = dbconnect.cursor()
    if isinstance(dic_json,dict): #判断是否是字典类型isinstance 返回True false
        for key in dic_json:
            add_mes = {
                'keys': key,
                'starts': start,
            }   
            try:
                cursor.execute(addSQL,add_mes)
                dbconnect.commit()
            except Exception as e:
                print("插入失败!")
                traceback.print_exc()
                print(e.with_traceback)
def insertDB(mes,dbconnect):
    updateSQL= ("INSERT INTO keyvalue (`keys`,`starts`,`types`,`lens`) "
        "VALUES(%(keys)s,%(starts)s,%(types)s,%(lens)s)")
    start=mes.decode('utf8').split(':')[0]
    start=start[2:].replace('"','')
    dic_json = json.loads(mes)
    cursor = dbconnect.cursor()
    if isinstance(dic_json,dict): #判断是否是字典类型isinstance 返回True false
        for key in dic_json:
            add_mes = {
                'keys': key,
                'starts': start,
                'types': str(type(dic_json[key])),
                'lens': len(str(dic_json[key])),
            }   
            try:
                cursor.execute(updateSQL,add_mes)
                dbconnect.commit()
            except Exception as e:
                print("更新失败!")
                traceback.print_exc()
                print(e.with_traceback)

def updateDB(mes,dbconnect):
    updateSQL= ("UPDATE keyvalue SET counts=counts+1 "
        "WHERE `keys`=%(keys)s AND `starts`=%(starts)s")
    start=mes.decode('utf8').split(':')[0]
    start=start[2:].replace('"','')
    dic_json = json.loads(mes)
    cursor = dbconnect.cursor()
    if isinstance(dic_json,dict): #判断是否是字典类型isinstance 返回True false
        for key in dic_json:
            add_mes = {
                'keys': key,
                'starts': start,
            }   
            try:
                cursor.execute(updateSQL,add_mes)
                dbconnect.commit()
            except Exception as e:
                print("更新失败!")
                traceback.print_exc()
                print(e.with_traceback)
        
async def startup(uri,dbconnect):
    async with AioWebSocket(uri) as aws:
        converse = aws.manipulator
        # 客户端给服务端发送消息
        sendstr = '{'+'"SESSION_ID":"-593024204","SESSION_NAME":"全部告警2021-10-03 20:08:39.018 9.234453268703845","HOST_IP":"*.*.*.*","USER_ID":"263567140083","USER_NAME":"姜虎兵","FILTER_ID":[-1895577500],"MODEULE_TYPE":1,"msg_type":1,"START_TIME":"2021-09-03 20:08:33","END_TIME":"{time}"'.format(time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'))+'}'

        await converse.send(sendstr)
        #通过bool类型避免重复发送心跳数据包
        sendMessgae=True
        longmes=bytes()
        bend ='}'.encode('utf8')
        bstar ='{'.encode('utf8')
        while True:
            mes =await converse.receive()
            try:
                strmes=mes.decode('utf8').strip()
            except Exception as e :
                print(e)
                continue
            lenmes=len(strmes)
            #先丢弃不正常的包
            if lenmes < 10:
                print("丢弃长度过短的包,长度为:"+str(lenmes))
                await converse.send(sendstr)
                continue
            time=datetime.now().strftime('%Y-%m-%d %H:%M:%S')
            #对数据包进行判断
            #如果json包完整,进行如下处理:
            if strmes.startswith("{") and strmes.endswith("}"):
                insertDB(mes,dbconnect)
            elif strmes.startswith("{"):
                longmes=mes
            elif strmes.endswith("}"):
                longmes=longmes+mes
                insertDB(longmes,dbconnect)
                longmes=bytes()
            else:
                try:
                    print("frame不正常\n"
                        +str(lenmes)+"\n"
                        +mes.decode('utf8'))
                except Exception as e:
                    print(e)
                continue
            #循环发送心跳数据包
            if str(time).endswith("59") or str(time).endswith("29"):
                if sendMessgae:
                    message='{'+f'"msg":"ping","msg_type":"2","update_time":"{time}'+'"}'
                    print(message)
                    await converse.send(sendstr)
                    sendMessgae=False
            else:
                sendMessgae=True            
            #jsonmes=json.dumps(mes.decode('utf-8'))
            '''     
            
            add_mes = {
                'gdate': time,
                'message': jsonmes,
            }    

            try:
                cursor.execute(addSQL, add_mes)
                dbconnect.commit()
            except Exception as e:
                print("插入失败!")
                print(e.with_traceback)

'''   

if __name__ == '__main__':
    remote = 'ws://*.*.*.*:8080/webSocketAlarm'
    dbconnect = pymysql.connect(host="localhost", user="root", password="****", database="***",charset="utf8")
    try:
        asyncio.get_event_loop().run_until_complete(startup(remote,dbconnect))
    except KeyboardInterrupt as exc:
        logging.info('Quit.')

ps: 主要问题的原因是websockets推送数据速度大于本地客户端及MySQL存储数据的速度。
以上代码通过线程锁的方式进行解决。
下面文章是线程问题,可以参考一下

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值