HiveNetWebUtils.utils.socket 源代码
#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# Copyright 2022 黎慧剑
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
socket连接的工具类
@module socket
@file socket.py
"""
import sys
import os
import socket
import asyncio
import datetime
from HiveNetCore.generic import CResult, NullObj
from HiveNetCore.utils.exception_tool import ExceptionTool
from HiveNetCore.utils.run_tool import AsyncTools
# 根据当前文件路径将包路径纳入, 在非安装的情况下可以引用到
sys.path.append(os.path.abspath(os.path.join(
os.path.dirname(__file__), os.path.pardir, os.path.pardir)))
[文档]class SocketTool(object):
"""
socket连接的工具类
"""
[文档] @classmethod
def connect(cls, connect_config={}) -> CResult:
"""
连接Socket服务器端并返回连接对象
@param {dict} connect_config - 连接参数
ip {str} - 主机名或IP地址, 默认为'127.0.0.1'
port {int} - 监听端口, 默认为8080
recv_timeout {float} - 数据接收的超时时间, 单位为秒, 默认为10.0
send_timeout {float} - 数据发送的超时时间, 单位为秒, 默认为10.0
@returns {CResult} - 连接结果:
result.code: '00000'-成功, 其他值为失败
result.net_info: 连接后的网络信息对象
net_info.csocket - socket对象
net_info.laddr 本地地址,地址对象("IP地址",打开端口)
net_info.raddr 远端地址,地址对象("IP地址",打开端口)
net_info.send_timeout 发送超时时间, 单位为秒
net_info.recv_timeout 收取超时时间, 单位为秒
"""
# 子类必须定义该功能
_result = CResult('00000')
_result.net_info = None
with ExceptionTool.ignored_cresult(
_result, logger=None
):
# 进行连接
_tcp_cli_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 分配 TCP 客户端套接字
_tcp_cli_sock.connect(
(connect_config.get('ip', '127.09.0.1'), connect_config.get('port', 8080))
) # 主动连接
_tcp_cli_sock.setblocking(False) # 将socket设置为非阻塞. 在创建socket对象后就进行该操作.
# 处理网络连接对象
_result.net_info = NullObj()
_result.net_info.csocket = _tcp_cli_sock
_result.net_info.laddr = _tcp_cli_sock.getsockname()
_result.net_info.raddr = _tcp_cli_sock.getpeername()
_result.net_info.send_timeout = connect_config.get('send_timeout', 10.0)
_result.net_info.recv_timeout = connect_config.get('recv_timeout', 10.0)
return _result
[文档] @classmethod
def close(cls, net_info: NullObj):
"""
关闭指定的网络连接
@param {NullObj} net_info - 需要关闭的网络连接信息对象
net_info.csocket - socket对象
net_info.laddr 本地地址,地址对象("IP地址",打开端口)
net_info.raddr 远端地址,地址对象("IP地址",打开端口)
net_info.send_timeout 发送超时时间, 单位为秒
net_info.recv_timeout 收取超时时间, 单位为秒
@returns {CResult} - 关闭结果
result.code: '00000'-成功, 其他值为失败
"""
_result = CResult('00000')
with ExceptionTool.ignored_cresult(
_result, logger=None
):
net_info.csocket.close()
return _result
[文档] @classmethod
def recv_data(cls, net_info, recv_para={}):
"""
从指定的网络连接中读取数据
@param {NullObj} net_info - 网络连接信息对象
net_info.csocket - socket对象
net_info.laddr 本地地址,地址对象("IP地址",打开端口)
net_info.raddr 远端地址,地址对象("IP地址",打开端口)
net_info.send_timeout 发送超时时间, 单位为秒
net_info.recv_timeout 收取超时时间, 单位为秒
@param {dict} recv_para - 读取数据的参数, 包括:
recv_len {int} - 要获取的数据长度, 必要参数
overtime {float} - 获取超时时间, 单位为秒, 非必要参数
@returns {CResult} - 数据获取结果:
result.code: '00000'-成功, '20403'-获取数据超时, 其他为获取失败
result.data: 获取到的数据对象(具体类型和定义, 由实现类自定义)
result.recv_time : datetime 实际开始接受数据时间
result.overtime : float 超时时间(秒), 当返回结果为超时, 可获取超时时间信息
"""
if not isinstance(recv_para, dict):
recv_para = {}
_result = CResult('00000')
_result.data = b''
_result.recv_time = datetime.datetime.now()
_overtime = recv_para.get('overtime', None)
if _overtime is None:
if hasattr(net_info, 'recv_timeout'):
_overtime = net_info.recv_timeout
else:
_overtime = 10.0
_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() > _overtime:
# 已超时
_result.change_code(code='20403')
break
_buffer = b''
with ExceptionTool.ignored(expect=(BlockingIOError)):
# 获取数据
_buffer = net_info.csocket.recv(_rest_bytes)
if _buffer is not None and len(_buffer) > 0:
_result.data = _result.data + _buffer
_rest_bytes = _rest_bytes - len(_buffer)
else:
# 休眠一下
AsyncTools.sync_run_coroutine(
asyncio.sleep(0.001)
)
return _result
[文档] @classmethod
def send_data(cls, net_info, data: bytes, send_para={}):
"""
向指定的网络连接发送数据
@param {NullObj} net_info - 网络连接信息对象
net_info.csocket - socket对象
net_info.laddr 本地地址,地址对象("IP地址",打开端口)
net_info.raddr 远端地址,地址对象("IP地址",打开端口)
net_info.send_timeout 发送超时时间, 单位为秒
net_info.recv_timeout 收取超时时间, 单位为秒
@param {bytes} data - 要写入的数据对象
@param {dict} send_para - 写入数据的参数:
overtime {float} - 发送超时时间, 单位为秒, 非必须参数
@returns {CResult} - 发送结果:
result.code: '00000'-成功, '20404'-写入数据超时, 其他为写入失败
result.send_time : datetime 实际发送完成时间
result.overtime : float 超时时间(秒), 当返回结果为超时, 可获取超时时间信息
"""
if not isinstance(send_para, dict):
send_para = {}
_result = CResult('00000')
_result.send_time = None
_overtime = send_para.get('overtime', None)
if _overtime is None:
if hasattr(net_info, 'send_timeout'):
_overtime = net_info.send_timeout
else:
_overtime = 10.0
_result.overtime = _overtime
_begin_time = datetime.datetime.now()
with ExceptionTool.ignored_cresult(
_result
):
_rest_bytes = len(data)
_total_bytes = _rest_bytes
while _rest_bytes > 0:
# 检查是否超时
if (datetime.datetime.now() - _begin_time).total_seconds() > _overtime:
# 已超时
_result.change_code(code='20404')
break
with ExceptionTool.ignored(expect=(BlockingIOError)):
# 发送数据
_len = net_info.csocket.send(data[_total_bytes - _rest_bytes:])
if _len > 0:
_rest_bytes = _rest_bytes - _len
_result.send_time = datetime.datetime.now()
return _result