spin6lock / python-sproto

python binding to sproto

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

sproto_decode提示sproto c lib error

3638836363 opened this issue · comments

Linux version 2.6.32-754.35.1.el6.x86_64 (mockbuild@x86-02.bsys.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-23) (GCC) ) #1 SMP Sat Nov 7 12:42:14 UTC 2020

python 3.11.1
pysproto 0.1.4

函数调用

    import pysproto as core

    msg = core.sproto_decode(st, chunk)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

解析消息时大概率提示[sproto c lib error](pysproto.error: sproto c lib error)

message:b']\x02\x16\xbd\x02\x02\x10&\x11"\x03\x14\x08\x04\x13m\xc3\x0eQ\x02\xca\x04Lm\xc3\x0cD\x08\x03\x15\n\x01\x06', error:sproto c lib error

使用同样的内容去解析b']\x02\x16\xbd\x02\x02\x10&\x11"\x03\x14\x08\x04\x13m\xc3\x0eQ\x02\xca\x04Lm\xc3\x0cD\x08\x03\x15\n\x01\x06'
当我尝试在函数调用前打印信息时,居然可以正常解析了

import pysproto as core

    print('') #加一个空打印就不会报错了
    msg = core.sproto_decode(st, chunk)

再次测试把print去除,就会提示pysproto.error: sproto c lib error

能提供下可以复现的例子么?sproto没有定义文件没法从二进制decode的,另外有可能是前面代码把栈搞坏了,print刚好修好了,我回头也看看代码,希望能提供下前面还调了什么接口的信息

#decode函数

class Sproto(object):

    def __init__(self, chunk):
        self.sp = core.sproto_create(chunk)
        self.st = {}
        self.proto = {}

    def querytype(self, tagname):
        if not tagname in self.st:
            self.st[tagname] = core.sproto_type(self.sp, tagname)
        return self.st[tagname]

    def protocol(self, protoname):
        # print(protoname)
        if not protoname in self.proto:
            self.proto[protoname] = core.sproto_protocol(self.sp, protoname)
        return self.proto[protoname]

    def encode(self, st, data):
        if isinstance(st, str):
            st = self.querytype(st)
        return core.sproto_encode(st, data)

    def decode(self, st, chunk):
        if isinstance(st, str):
            st = self.querytype(st)
        msg = core.sproto_decode(st, chunk)  
        return msg

#外部调用方式

def dispatch(self, data):
    sp = self._s2c
    data = sp.unpack(data)
    header, size = sp.decode(self._package, data)
    content = data[size:]
    if header.get("type", 0):
        protoname, req, _ = sp.protocol(header["type"])
        result, _ = sp.decode(req, content) if req else None
        ret = {"type": "REQUEST", "proto": protoname, "msg": result, "session": None}
        if header.get("session", 0):
            ret["session"] = header["session"] 

将打印代码取消,写了一个重试机制去decode

def delayMicrosecond(t):    
    start,end=0,0
    start=time.time()
    t=(t-3)/1000000
    while end-start<t:
        end=time.time() 

    
while 1:
    try:
        msg = core.sproto_decode(st, chunk)
        return msg
    except Exception as e:
        delayMicrosecond(10) # 延时10微秒
        # time.sleep(0.001) # 延时1毫秒
        # print('重试')
        continue

发现使用time.sleep还是微秒等待都可以在重试1-2次后正常。
重试时的效果,都是tcp请求和接收,这边把C2S业务都打印出来,如’业务5‘多次请求,但是是偶发报错。

User|03:49:50|Send[215]|DEBUG: c2s ===>: {'type': '业务0', 'session': 1, 'msg': {}}
set string:map key type not support
set string:sproto c lib error
重试
User|03:49:50|Send[215]|DEBUG: c2s ===>: {'type': '业务1', 'session': 2, 'msg': {请求内容}}
User|03:49:50|Send[215]|DEBUG: c2s ===>: {'type': '业务2', 'session': 3, 'msg': {请求内容}}
set string:map key type not support
set string:sproto c lib error
重试
User|03:49:51|Send[215]|DEBUG: c2s ===>: {'type': '业务3', 'session': 4, 'msg': {}}
User|03:49:51|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 5, 'msg': {请求内容}}
User|03:49:51|Send[215]|DEBUG: c2s ===>: {'type': '业务5', 'session': 6, 'msg': {请求内容}}
set string:map key type not support
set string:sproto c lib error
重试
User|03:49:52|Send[215]|DEBUG: c2s ===>: {'type': '业务6', 'session': 7, 'msg': {请求内容}}
User|03:49:52|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 8, 'msg': {请求内容}}
User|03:49:53|Send[215]|DEBUG: c2s ===>: {'type': '业务5', 'session': 9, 'msg': {请求内容}}
User|03:49:53|Send[215]|DEBUG: c2s ===>: {'type': '业务5', 'session': 10, 'msg': {请求内容}}
User|03:49:53|Send[215]|DEBUG: c2s ===>: {'type': '业务6', 'session': 11, 'msg': {请求内容}}
User|03:49:54|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 12, 'msg': {请求内容}}
User|03:49:55|Send[215]|DEBUG: c2s ===>: {'type': '业务6', 'session': 13, 'msg': {请求内容}}
User|03:49:56|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 14, 'msg': {请求内容}}
User|03:49:56|Send[215]|DEBUG: c2s ===>: {'type': '业务6', 'session': 15, 'msg': {请求内容}}
User|03:49:57|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 16, 'msg': {请求内容}}
User|03:49:57|Send[215]|DEBUG: c2s ===>: {'type': '业务5', 'session': 17, 'msg': {请求内容}}
User|03:49:57|Send[215]|DEBUG: c2s ===>: {'type': '业务6', 'session': 18, 'msg': {请求内容}}
User|03:49:58|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 19, 'msg': {请求内容}}
User|03:49:58|Send[215]|DEBUG: c2s ===>: {'type': '业务6', 'session': 20, 'msg': {请求内容}}
User|03:49:59|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 21, 'msg': {请求内容}}
User|03:49:59|Send[215]|DEBUG: c2s ===>: {'type': '业务7', 'session': 22, 'msg': {请求内容}}
User|03:50:00|Send[215]|DEBUG: c2s ===>: {'type': '业务8', 'session': 23, 'msg': {请求内容}}
User|03:50:01|Send[215]|DEBUG: c2s ===>: {'type': '业务8', 'session': 24, 'msg': {请求内容}}
User|03:50:01|Send[215]|DEBUG: c2s ===>: {'type': '业务9', 'session': 25, 'msg': {}}
User|03:50:01|Send[215]|DEBUG: c2s ===>: {'type': '业务10', 'session': 26, 'msg': {请求内容}}
User|03:50:02|Send[215]|DEBUG: c2s ===>: {'type': '业务11', 'session': 27, 'msg': {}}
User|03:50:02|Send[215]|DEBUG: c2s ===>: {'type': '业务12', 'session': 28, 'msg': {请求内容}}
set string:map key type not support
set string:sproto c lib error
重试
User|03:50:02|Send[215]|DEBUG: c2s ===>: {'type': '业务12', 'session': 29, 'msg': {请求内容}}
User|03:50:03|Send[215]|DEBUG: c2s ===>: {'type': '业务12', 'session': 30, 'msg': {请求内容}}
User|03:50:03|Send[215]|DEBUG: c2s ===>: {'type': '业务12', 'session': 31, 'msg': {请求内容}}
User|03:50:04|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 32, 'msg': {请求内容}}
User|03:50:04|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 33, 'msg': {请求内容}}
User|03:50:04|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 34, 'msg': {请求内容}}
User|03:50:04|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 35, 'msg': {请求内容}}
User|03:50:04|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 36, 'msg': {请求内容}}
User|03:50:04|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 37, 'msg': {请求内容}}
User|03:50:05|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 38, 'msg': {请求内容}}
User|03:50:08|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 39, 'msg': {请求内容}}
User|03:50:11|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 40, 'msg': {请求内容}}
User|03:50:13|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 41, 'msg': {请求内容}}
User|03:50:16|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 42, 'msg': {请求内容}}
User|03:50:18|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 43, 'msg': {请求内容}}
User|03:50:21|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 44, 'msg': {请求内容}}
User|03:50:23|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 45, 'msg': {请求内容}}
User|03:50:25|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 46, 'msg': {请求内容}}
User|03:50:27|Send[215]|DEBUG: c2s ===>: {'type': '业务13', 'session': 47, 'msg': {请求内容}}
User|03:50:30|Send[215]|DEBUG: c2s ===>: {'type': '业务14', 'session': 48, 'msg': {请求内容}}
set string:map key type not support
set string:sproto c lib error
重试

于是将print换time.sleep,设置延时1毫秒,也是可以重试成功,包括后面降到10微秒也是正常重试成功。

User|03:56:24|Send[215]|DEBUG: c2s ===>: {'type': '业务1', 'session': 1, 'msg': {}}
User|03:56:24|Send[215]|DEBUG: c2s ===>: {'type': '业务2', 'session': 2, 'msg': {请求内容}}
User|03:56:24|Send[215]|DEBUG: c2s ===>: {'type': '业务3', 'session': 3, 'msg': {请求内容}}
set string:map key type not support
set string:sproto c lib error
User|03:56:25|Send[215]|DEBUG: c2s ===>: {'type': '业务3', 'session': 4, 'msg': {请求内容}}
User|03:56:25|Send[215]|DEBUG: c2s ===>: {'type': '业务3', 'session': 5, 'msg': {请求内容}}
User|03:56:26|Send[215]|DEBUG: c2s ===>: {'type': '业务3', 'session': 6, 'msg': {请求内容}}
User|03:56:26|Send[215]|DEBUG: c2s ===>: {'type': '业务4', 'session': 7, 'msg': {请求内容}}
set string:map key type not support
set string:sproto c lib error
User|03:56:26|Send[215]|DEBUG: c2s ===>: {'type': '业务5', 'session': 8, 'msg': {}}
User|03:56:27|Send[215]|DEBUG: c2s ===>: {'type': '业务6', 'session': 9, 'msg': {请求内容}}
User|03:56:27|Send[215]|DEBUG: c2s ===>: {'type': '业务7', 'session': 10, 'msg': {请求内容}}
set string:map key type not support
set string:sproto c lib error
User|03:56:27|Send[215]|DEBUG: c2s ===>: {'type': '业务7', 'session': 11, 'msg': {请求内容}}
User|03:56:27|Send[215]|DEBUG: c2s ===>: {'type': '业务8', 'session': 12, 'msg': {请求内容}}
User|03:56:28|Send[215]|DEBUG: c2s ===>: {'type': '业务6', 'session': 13, 'msg': {请求内容}}

总结:
相同业务在同个环境下执行可能decode成功也可能失败。加入延时可以正常重试,也不用担心控制台过多内容展示,目前重试这个办法可以解决’sproto c lib error‘这个问题且不影响使用。

另外只是一个假设的推导。之前在python3.6版本很小概率会出现’sproto c lib error‘这个错误,现在python3.11(理论上性能比3.6强很多)版本下边的更频繁了一点,所以更好的暴露了这个问题。

我重新看了一下decode的代码,全局的对象只有SprotoError,理论上只要输入确定,结果一定是确定的,输入如果解不开,重试也应该解不开才对。具体到报错,我看你贴出来的日志里提示map key type not support,这个是说调用了sproto_decode解码一个字典的key值,返回值不是负数,但是data却是nil

因为前文只有一串二进制]\x02\x16\xbd\x02\x02\x10&\x11"\x03\x14\x08\x04\x13m\xc3\x0eQ\x02\xca\x04Lm\xc3\x0cD\x08\x03\x15\n\x01\x06 ,没有配套的sproto定义,没法写到单元测试里单独测试,难以确定是不是库的解码有问题。如果sproto定义是敏感信息不方便公开,可以参考代码里的test目录测试用例写法,尝试复现下解码问题,比如test/test_wild_pointer.py 就是一个不错的例子。也可以打开python_sproto.c:274 调试语句重新编译看看sub.map_key有没有解出来:

printf("%s:%s\n", PyString_AsString(PyObject_Str(sub.map_key)), PyString_AsString(PyObject_Str(sub.table)));

另外,还想了解一下这里有涉及到多线程环境么?

我在f3b2e3a 上加了更多的打印,有机会的话可以更新试试,看是不是有新类型没支持解析

我在f3b2e3a 上加了更多的打印,有机会的话可以更新试试,看是不是有新类型没支持解析

https://github.com/spin6lock/python-sproto/commit/f3b2e3a60fa78f376231eac3f278be2b7ebf2c42基础上使用,没有新增新的报错。

我重新看了一下decode的代码,全局的对象只有SprotoError,理论上只要输入确定,结果一定是确定的,输入如果解不开,重试也应该解不开才对。具体到报错,我看你贴出来的日志里提示map key type not support,这个是说调用了sproto_decode解码一个字典的key值,返回值不是负数,但是data却是nil

因为前文只有一串二进制]\x02\x16\xbd\x02\x02\x10&\x11"\x03\x14\x08\x04\x13m\xc3\x0eQ\x02\xca\x04Lm\xc3\x0cD\x08\x03\x15\n\x01\x06 ,没有配套的sproto定义,没法写到单元测试里单独测试,难以确定是不是库的解码有问题。如果sproto定义是敏感信息不方便公开,可以参考代码里的test目录测试用例写法,尝试复现下解码问题,比如test/test_wild_pointer.py 就是一个不错的例子。也可以打开python_sproto.c:274 调试语句重新编译看看sub.map_key有没有解出来:

printf("%s:%s\n", PyString_AsString(PyObject_Str(sub.map_key)), PyString_AsString(PyObject_Str(sub.table)));

另外,还想了解一下这里有涉及到多线程环境么?

使用的时候没有用到多线程。
这段时间的使用观察来看,同样的内容去decode,有时失败有时成功,不过加入失败重试这个问题也解决了。由于不好复现,以后遇到具体问题的话在具体跟踪,这个先关闭。

更新了sproto.c到上游版本,修复空数组的问题,应该能解决了

之前的方式是在头部一次导入
import pysproto as core

...
core.sproto_decode(st, chunk)
仍然会出现
set string:map key type not support
set string:sproto c lib error
然后通过重试的方式来规避

后面尝试新的方案
每次调用sproto_decode时重新导入pysproto 就没有出现sproto c lib error了
import pysproto
pysproto.sproto_decode(st, chunk)