def recv_data(cls, net_info, recv_para={}): """ 从指定的网络连接中读取数据 @param {object} net_info - 要读取数据的网络信息对象(例如socket对象) @param {dict} recv_para - 读取数据的参数(暂时无用) @returns {CResult} - 数据获取结果: result.code :'00000'-成功,'20403'-获取数据超时,其他为获取失败 result.data :获取到的数据对象,为一个二元数组 (proto_msg, msg) - MsgHTTP报文头,二进制报文数据 result.recv_time : datetime 实际开始接受数据时间 """ # 子类必须定义该功能 if type(recv_para) != dict: recv_para = {} _result = CResult('00000') _result.data = None _result.recv_time = datetime.datetime.now() with ExceptionTool.ignored_cresult( _result ): _head_result = cls.recv_http_head(net_info, recv_para) if not _head_result.is_success(): return _head_result _proto_msg = _head_result.data _body_result = cls.recv_http_body(net_info, _proto_msg, recv_para) if not _body_result.is_success(): return _body_result _result.data = (_proto_msg, _body_result.data) return _result
def recv_data(cls, net_info, recv_para={}): """ 从指定的网络连接中读取数据 @param {object} net_info - 要读取数据的网络信息对象(例如socket对象) @param {dict} recv_para - 读取数据的参数, 包括: recv_len {int} - 要获取的数据长度, 必要参数 overtime {int} - 获取超时时间,单位为毫秒,非必要参数 @returns {CResult} - 数据获取结果: result.code :'00000'-成功,'20403'-获取数据超时,其他为获取失败 result.data :获取到的数据对象(具体类型和定义,由实现类自定义) result.recv_time : datetime 实际开始接受数据时间 result.overtime : int 超时时间(毫秒),当返回结果为超时,可获取超时时间信息 """ # 子类必须定义该功能 if type(recv_para) != dict: recv_para = {} _result = CResult('00000') _result.data = b'' _result.recv_time = datetime.datetime.now() _overtime = 10000 if 'overtime' in recv_para.keys(): # 外部有传入,优先使用该超时时间 _overtime = recv_para['overtime'] elif hasattr(net_info, 'recv_timeout'): # 如果net_info有超时的设置 _overtime = net_info.recv_timeout _result.overtime = _overtime with ExceptionTool.ignored_cresult( _result ): _rest_bytes = recv_para['recv_len'] while _rest_bytes > 0: # 检查是否超时 if (datetime.datetime.now() - _result.recv_time).total_seconds() * 1000 > _overtime: # 已超时 _result.change_code(code='20403') break _buffer = b'' with ExceptionTool.ignored(expect=(BlockingIOError)): # 获取数据 _buffer = net_info.csocket.recv(_rest_bytes) if len(_buffer) > 0: _result.data = _result.data + _buffer _rest_bytes = _rest_bytes - len(_buffer) else: # 休眠一下 RunTool.sleep(0.001) return _result
def recv_http_body(cls, net_info, proto_msg, recv_para={}): """ 获取http报文体信息 @param {object} net_info - 要读取数据的网络信息对象 @param {MsgHTTP} proto_msg - http报文头 @param {dict} recv_para - 获取参数,暂未使用 @returns {CResult} - 数据获取结果: result.code :'00000'-成功,'20403'-获取数据超时,其他为获取失败 result.msg :获取到的数据对象,类型为bytes result.recv_time : datetime 实际开始接受数据时间 """ if type(recv_para) != dict: recv_para = {} _recv_para = copy.deepcopy(recv_para) _result = CResult('00000') _result.data = None _result.recv_time = datetime.datetime.now() with ExceptionTool.ignored_cresult( _result ): _get_value = proto_msg.get_value(search_path='Content-Length') if _get_value is not None: _len = int(_get_value) _recv_para['recv_len'] = _len _recv_result = TcpIpService.recv_data(net_info, _recv_para) _result = _recv_result return _result
def recv_http_head(cls, net_info, recv_para={}): """ 获取http报文头对象 @param {object} net_info - 要读取数据的网络信息对象 @param {dict} recv_para - 获取参数,暂未使用 @returns {CResult} - 数据获取结果: result.code :'00000'-成功,'20403'-获取数据超时,其他为获取失败 result.data :获取到的数据对象,类型为MsgHTTP result.recv_time : datetime 实际开始接受数据时间 """ if type(recv_para) != dict: recv_para = {} _result = CResult('00000') _result.data = None _result.recv_time = datetime.datetime.now() _overtime = 10000 if 'overtime' in recv_para.keys(): # 外部有传入,优先使用该超时时间 _overtime = recv_para['overtime'] elif hasattr(net_info, 'recv_timeout'): # 如果net_info有超时的设置 _overtime = net_info.recv_timeout _result.overtime = _overtime _recv_para = copy.deepcopy(recv_para) _recv_para['recv_len'] = 1 with ExceptionTool.ignored_cresult( _result ): # 循环获取所有报文头内容 _get_line_bytes = b'' _last_is_ln = False # 标记上一个字符是否回车换行 while True: # 检查是否超时 if (datetime.datetime.now() - _result.recv_time).total_seconds() * 1000 > _overtime: # 已超时 _result.change_code(code='20403') break _read_result = TcpIpService.recv_data(net_info, _recv_para) if not _read_result.is_success(): # 出现异常,直接返回失败 _read_result.data = None _read_result.recv_time = _result.recv_time return _read_result # 获取成功,判断是否回车换行 _get_line_bytes = _get_line_bytes + _read_result.data if str(_read_result.data, "ascii") == "\n" and _last_is_ln: # 已经连续遇到两次回车换行,说明报文头已收齐退出循环 break elif str(_read_result.data, "ascii") == "\n": _last_is_ln = True continue elif str(_read_result.data, "ascii") == "\r": continue else: # 其他字符,不是连续换行 _last_is_ln = False continue # 取完报文头数据,转换为结构对象 _result.data = MsgHTTP(_get_line_bytes, msg_id=None, obj_type=EnumMsgObjType.Bytes) return _result