socket-cyg 0.1.6__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {socket_cyg-0.1.6 → socket_cyg-1.1.0}/PKG-INFO +2 -2
- {socket_cyg-0.1.6 → socket_cyg-1.1.0}/pyproject.toml +1 -1
- socket_cyg-1.1.0/socket_cyg/example/client_example.py +18 -0
- socket_cyg-1.1.0/socket_cyg/socket_client.py +126 -0
- socket_cyg-1.1.0/socket_cyg/socket_server_asyncio.py +127 -0
- socket_cyg-0.1.6/socket_cyg/example/client_example.py +0 -43
- socket_cyg-0.1.6/socket_cyg/example/server_example.py +0 -31
- socket_cyg-0.1.6/socket_cyg/socket_client.py +0 -125
- socket_cyg-0.1.6/socket_cyg/socket_server_asyncio.py +0 -133
- {socket_cyg-0.1.6 → socket_cyg-1.1.0}/README.md +0 -0
- {socket_cyg-0.1.6 → socket_cyg-1.1.0}/socket_cyg/__init__.py +0 -0
- {socket_cyg-0.1.6 → socket_cyg-1.1.0}/socket_cyg/example/__init__.py +0 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
# pylint: skip-file
|
2
|
+
import time
|
3
|
+
|
4
|
+
from socket_cyg.socket_client import SocketClient
|
5
|
+
|
6
|
+
|
7
|
+
if __name__ == "__main__":
|
8
|
+
def my_callback(data: bytes):
|
9
|
+
"""示例回调函数。"""
|
10
|
+
print(f"回调收到数据: {data.decode('UTF-8')}")
|
11
|
+
|
12
|
+
client = SocketClient("127.0.0.1", 9001, my_callback)
|
13
|
+
if client.connect():
|
14
|
+
try:
|
15
|
+
client.send_data(b"ffffff")
|
16
|
+
time.sleep(500000)
|
17
|
+
finally:
|
18
|
+
client.disconnect()
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# pylint: skip-file
|
2
|
+
|
3
|
+
import socket
|
4
|
+
import threading
|
5
|
+
import logging
|
6
|
+
from typing import Callable, Optional
|
7
|
+
|
8
|
+
|
9
|
+
class SocketClient:
|
10
|
+
"""用于持续与服务器通信的 TCP Socket 客户端."""
|
11
|
+
|
12
|
+
def __init__(self, host: str, port: int,
|
13
|
+
receive_callback: Optional[Callable[[bytes], None]] = None,
|
14
|
+
buffer_size: int = 1024):
|
15
|
+
"""初始化 Socket 客户端.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
host: 要连接的服务器主机名或 IP 地址.
|
19
|
+
port: 服务器端口号.
|
20
|
+
receive_callback: 处理接收数据的回调函数, 回调函数应接受 bytes 类型作为唯一参数.
|
21
|
+
buffer_size: 接收缓冲区大小(字节),默认为 1024.
|
22
|
+
"""
|
23
|
+
self.host = host
|
24
|
+
self.port = port
|
25
|
+
self.buffer_size = buffer_size
|
26
|
+
self.receive_callback = receive_callback
|
27
|
+
self.socket = None
|
28
|
+
self.is_connected = False
|
29
|
+
self.receive_thread = None
|
30
|
+
self.logger = logging.getLogger(self.__class__.__name__)
|
31
|
+
|
32
|
+
def connect(self) -> bool:
|
33
|
+
"""建立与服务器的连接, 连接成功后会自动启动后台线程持续接收数据.
|
34
|
+
|
35
|
+
Returns:
|
36
|
+
bool: 连接成功返回 True,否则返回 False.
|
37
|
+
"""
|
38
|
+
try:
|
39
|
+
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
40
|
+
self.socket.connect((self.host, self.port))
|
41
|
+
self.is_connected = True
|
42
|
+
self.logger.info("已连接到服务器 %s: %s", self.host, self.port)
|
43
|
+
|
44
|
+
self.receive_thread = threading.Thread(
|
45
|
+
target=self._receive_data,
|
46
|
+
daemon=True
|
47
|
+
)
|
48
|
+
self.receive_thread.start()
|
49
|
+
return True
|
50
|
+
except Exception as e:
|
51
|
+
self.logger.warning("连接失败, %s", str(e))
|
52
|
+
self.is_connected = False
|
53
|
+
return False
|
54
|
+
|
55
|
+
def disconnect(self):
|
56
|
+
"""断开与服务器的连接并释放资源."""
|
57
|
+
if self.is_connected:
|
58
|
+
self.is_connected = False
|
59
|
+
try:
|
60
|
+
if self.socket:
|
61
|
+
self.socket.close()
|
62
|
+
if self.receive_thread and self.receive_thread.is_alive():
|
63
|
+
self.receive_thread.join(timeout=1)
|
64
|
+
except Exception as e:
|
65
|
+
self.logger.warning("断开连接时出错: %s", str(e))
|
66
|
+
finally:
|
67
|
+
self.logger.info("已断开与服务器的连接")
|
68
|
+
|
69
|
+
def send_data(self, data: bytes) -> bool:
|
70
|
+
"""向服务器发送数据.
|
71
|
+
|
72
|
+
Args:
|
73
|
+
data: 要发送的字节数据.
|
74
|
+
|
75
|
+
Returns:
|
76
|
+
发送成功返回 True,失败返回 False.
|
77
|
+
|
78
|
+
Raises:
|
79
|
+
无显式抛出异常,但内部错误会打印到控制台.
|
80
|
+
"""
|
81
|
+
if not self.is_connected:
|
82
|
+
self.logger.warning("未连接到服务器")
|
83
|
+
return False
|
84
|
+
|
85
|
+
try:
|
86
|
+
self.socket.sendall(data)
|
87
|
+
return True
|
88
|
+
except Exception as e:
|
89
|
+
self.logger.warning("发送数据出错: %s", str(e))
|
90
|
+
self.disconnect()
|
91
|
+
return False
|
92
|
+
|
93
|
+
def _receive_data(self):
|
94
|
+
"""持续接收数据的内部方法."""
|
95
|
+
while self.is_connected:
|
96
|
+
try:
|
97
|
+
data = self.socket.recv(self.buffer_size)
|
98
|
+
if not data: # 服务器关闭连接
|
99
|
+
self.logger.info("服务器关闭了连接")
|
100
|
+
self.disconnect()
|
101
|
+
break
|
102
|
+
|
103
|
+
if self.receive_callback:
|
104
|
+
self.logger.info("收到数据: %s", data)
|
105
|
+
self.logger.info("触发回调函数")
|
106
|
+
self.receive_callback(data)
|
107
|
+
else:
|
108
|
+
self.logger.info("收到数据: %s", data)
|
109
|
+
except ConnectionResetError:
|
110
|
+
self.logger.warning("连接被服务器重置")
|
111
|
+
self.disconnect()
|
112
|
+
break
|
113
|
+
except Exception as e:
|
114
|
+
if self.is_connected:
|
115
|
+
self.logger.warning("接收数据出错: %s", str(e))
|
116
|
+
self.disconnect()
|
117
|
+
break
|
118
|
+
|
119
|
+
def __enter__(self):
|
120
|
+
"""实现上下文管理协议,进入时自动连接."""
|
121
|
+
self.connect()
|
122
|
+
return self
|
123
|
+
|
124
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
125
|
+
"""实现上下文管理协议,退出时自动断开连接."""
|
126
|
+
self.disconnect()
|
@@ -0,0 +1,127 @@
|
|
1
|
+
# pylint: skip-file
|
2
|
+
"""异步socket."""
|
3
|
+
import asyncio
|
4
|
+
import datetime
|
5
|
+
import logging
|
6
|
+
import os
|
7
|
+
import pathlib
|
8
|
+
import socket
|
9
|
+
import sys
|
10
|
+
from asyncio import AbstractEventLoop
|
11
|
+
from logging.handlers import TimedRotatingFileHandler
|
12
|
+
|
13
|
+
|
14
|
+
class CygSocketServerAsyncio:
|
15
|
+
"""异步socket class."""
|
16
|
+
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s"
|
17
|
+
|
18
|
+
clients = {} # 保存已连接的client
|
19
|
+
tasks = {}
|
20
|
+
loop: AbstractEventLoop = None
|
21
|
+
|
22
|
+
def __init__(self, address="127.0.0.1", port=8000):
|
23
|
+
self._address = address
|
24
|
+
self._port = port
|
25
|
+
self.logger = logging.getLogger(__name__)
|
26
|
+
self._file_handler = None
|
27
|
+
self._initial_log_config()
|
28
|
+
|
29
|
+
def _initial_log_config(self) -> None:
|
30
|
+
"""日志配置."""
|
31
|
+
self._create_log_dir()
|
32
|
+
self.logger.addHandler(self.file_handler) # 保存日志
|
33
|
+
|
34
|
+
@staticmethod
|
35
|
+
def _create_log_dir():
|
36
|
+
"""判断log目录是否存在, 不存在就创建."""
|
37
|
+
log_dir = pathlib.Path(f"{os.getcwd()}/log")
|
38
|
+
if not log_dir.exists():
|
39
|
+
os.mkdir(log_dir)
|
40
|
+
|
41
|
+
@property
|
42
|
+
def file_handler(self) -> TimedRotatingFileHandler:
|
43
|
+
"""设置保存日志的处理器, 每隔 24h 自动生成一个日志文件.
|
44
|
+
|
45
|
+
Returns:
|
46
|
+
TimedRotatingFileHandler: 返回 TimedRotatingFileHandler 日志处理器.
|
47
|
+
"""
|
48
|
+
if self._file_handler is None:
|
49
|
+
self._file_handler = TimedRotatingFileHandler(
|
50
|
+
f"{os.getcwd()}/log/socket.log",
|
51
|
+
when="D", interval=1, backupCount=10, encoding="UTF-8"
|
52
|
+
)
|
53
|
+
self._file_handler.namer = self._custom_log_name
|
54
|
+
self._file_handler.setFormatter(logging.Formatter(self.LOG_FORMAT))
|
55
|
+
return self._file_handler
|
56
|
+
|
57
|
+
@staticmethod
|
58
|
+
def _custom_log_name(log_path: str):
|
59
|
+
"""自定义新生成的日志名称.
|
60
|
+
|
61
|
+
Args:
|
62
|
+
log_path: 原始的日志文件路径.
|
63
|
+
|
64
|
+
Returns:
|
65
|
+
str: 新生成的自定义日志文件路径.
|
66
|
+
"""
|
67
|
+
_, suffix, date_str = log_path.split(".")
|
68
|
+
new_log_path = f"{os.getcwd()}/log/socket_{date_str}.{suffix}"
|
69
|
+
return new_log_path
|
70
|
+
|
71
|
+
def operations_return_data(self, data: bytes):
|
72
|
+
"""操作返回数据."""
|
73
|
+
data = data.decode("UTF-8")
|
74
|
+
self.logger.warning("没有重写 operations_return_data 函数, 默认是回显.")
|
75
|
+
return data
|
76
|
+
|
77
|
+
async def socket_send(self, client_connection, data: bytes):
|
78
|
+
"""发送数据给客户端."""
|
79
|
+
if client_connection:
|
80
|
+
client_ip = client_connection.getpeername()
|
81
|
+
await self.loop.sock_sendall(client_connection, data)
|
82
|
+
self.logger.info("%s 发送成功, %s", client_ip, data)
|
83
|
+
else:
|
84
|
+
self.logger.info("发送数据 % 失败", data)
|
85
|
+
|
86
|
+
async def receive_send(self, client_connection: socket.socket):
|
87
|
+
"""接收后发送数据."""
|
88
|
+
client_ip = client_connection.getpeername()[0] # 获取连接客户端的ip
|
89
|
+
try:
|
90
|
+
while data := await self.loop.sock_recv(client_connection, 1024 * 1024):
|
91
|
+
self.logger.info("%s", "-" * 60)
|
92
|
+
self.logger.info("接收到客户端 %s 的数据: %s", client_ip, data.decode("UTF-8"))
|
93
|
+
send_data = self.operations_return_data(data) # 这个方法实现具体业务, 需要重写, 不重写回显
|
94
|
+
send_data_byte = send_data.encode("UTF-8") + b"\r\n"
|
95
|
+
await self.loop.sock_sendall(client_connection, send_data_byte)
|
96
|
+
self.logger.info("回复客户端 %s 的数据是: %s", client_ip, send_data)
|
97
|
+
self.logger.info("%s", "-" * 60)
|
98
|
+
except Exception as e: # pylint: disable=W0718
|
99
|
+
self.logger.warning("通讯出现异常, 异常信息是: %s", str(e))
|
100
|
+
finally:
|
101
|
+
self.clients.pop(client_ip)
|
102
|
+
self.tasks.get(client_ip).cancel()
|
103
|
+
self.logger.warning("客户端 %s 断开了", client_ip)
|
104
|
+
client_connection.close()
|
105
|
+
|
106
|
+
async def listen_for_connection(self, socket_server: socket):
|
107
|
+
"""异步监听连接."""
|
108
|
+
self.logger.info("服务端 %s 已启动,等待客户端连接", socket_server.getsockname())
|
109
|
+
|
110
|
+
while True:
|
111
|
+
self.loop = asyncio.get_running_loop()
|
112
|
+
client_connection, address = await self.loop.sock_accept(socket_server)
|
113
|
+
client_connection.setblocking(False)
|
114
|
+
self.clients.update({address[0]: client_connection})
|
115
|
+
self.tasks.update({
|
116
|
+
address[0]: self.loop.create_task(self.receive_send(client_connection))
|
117
|
+
})
|
118
|
+
self.logger.warning("客户端 %s 连接了", address)
|
119
|
+
|
120
|
+
async def run_socket_server(self):
|
121
|
+
"""运行socket服务, 并监听客户端连接."""
|
122
|
+
socket_server = socket.socket()
|
123
|
+
socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
124
|
+
socket_server.setblocking(False)
|
125
|
+
socket_server.bind((self._address, self._port))
|
126
|
+
socket_server.listen()
|
127
|
+
await self.listen_for_connection(socket_server)
|
@@ -1,43 +0,0 @@
|
|
1
|
-
"""client_example."""
|
2
|
-
import os
|
3
|
-
|
4
|
-
from socket_cyg.socket_client import SocketClient
|
5
|
-
|
6
|
-
|
7
|
-
FILE_PATH = r"D:\python_workspace\equipment_cyg.rar"
|
8
|
-
|
9
|
-
|
10
|
-
if __name__ == '__main__':
|
11
|
-
|
12
|
-
client1 = SocketClient()
|
13
|
-
client1.client_open()
|
14
|
-
client1.run_receive_thread()
|
15
|
-
with open(FILE_PATH, mode="rb+") as f:
|
16
|
-
data = f.read()
|
17
|
-
dir_path = f"{os.getcwd()}/a"
|
18
|
-
client1.client_send(dir_path.encode("UTF-8") + b"-_-" + data + b"@__@")
|
19
|
-
|
20
|
-
client2 = SocketClient()
|
21
|
-
client2.client_open()
|
22
|
-
client2.run_receive_thread()
|
23
|
-
with open(FILE_PATH, mode="rb+") as f:
|
24
|
-
data = f.read()
|
25
|
-
dir_path = f"{os.getcwd()}/b"
|
26
|
-
client2.client_send(dir_path.encode("UTF-8") + b"-_-" + data + b"@__@")
|
27
|
-
|
28
|
-
client3 = SocketClient()
|
29
|
-
client3.client_open()
|
30
|
-
client3.run_receive_thread()
|
31
|
-
with open(FILE_PATH, mode="rb+") as f:
|
32
|
-
data = f.read()
|
33
|
-
dir_path = f"{os.getcwd()}/c"
|
34
|
-
client3.client_send(dir_path.encode("UTF-8") + b"-_-" + data + b"@__@")
|
35
|
-
|
36
|
-
client4 = SocketClient()
|
37
|
-
client4.client_open()
|
38
|
-
client4.run_receive_thread()
|
39
|
-
with open(FILE_PATH, mode="rb+") as f:
|
40
|
-
data = f.read()
|
41
|
-
dir_path = f"{os.getcwd()}/d"
|
42
|
-
client4.client_send(dir_path.encode("UTF-8") + b"-_-" + data + b"@__@")
|
43
|
-
|
@@ -1,31 +0,0 @@
|
|
1
|
-
"""server_example."""
|
2
|
-
import asyncio
|
3
|
-
import os.path
|
4
|
-
import threading
|
5
|
-
|
6
|
-
from socket_cyg.socket_server_asyncio import CygSocketServerAsyncio
|
7
|
-
|
8
|
-
|
9
|
-
def save(data):
|
10
|
-
"""保存文件的函数."""
|
11
|
-
dir_path, datas = list(data.keys())[0], list(data.values())[0]
|
12
|
-
dir_path = dir_path.decode("UTF-8")
|
13
|
-
if not os.path.exists(dir_path):
|
14
|
-
os.makedirs(dir_path)
|
15
|
-
with open(f"{dir_path}/a.rar", "ab+") as f:
|
16
|
-
f.write(datas)
|
17
|
-
|
18
|
-
|
19
|
-
if __name__ == '__main__':
|
20
|
-
server = CygSocketServerAsyncio(end_identifier=b"@__@")
|
21
|
-
|
22
|
-
def run_server():
|
23
|
-
"""启动server."""
|
24
|
-
asyncio.run(server.run_socket_server())
|
25
|
-
|
26
|
-
def run_consumer():
|
27
|
-
"""启动消费队列."""
|
28
|
-
asyncio.run(server.consumer(save))
|
29
|
-
|
30
|
-
threading.Thread(target=run_server).start()
|
31
|
-
threading.Thread(target=run_consumer).start()
|
@@ -1,125 +0,0 @@
|
|
1
|
-
"""socket 客户端."""
|
2
|
-
import datetime
|
3
|
-
import os
|
4
|
-
import socket
|
5
|
-
import sys
|
6
|
-
import threading
|
7
|
-
import logging
|
8
|
-
from logging.handlers import TimedRotatingFileHandler
|
9
|
-
from typing import Union
|
10
|
-
|
11
|
-
|
12
|
-
class SocketClient:
|
13
|
-
"""socket 客户端class."""
|
14
|
-
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s"
|
15
|
-
|
16
|
-
|
17
|
-
def __init__(self, host="127.0.0.1", port=8000):
|
18
|
-
self._logger = logging.getLogger(f"{self.__module__}.{self.__class__.__name__}")
|
19
|
-
self._file_handler = None
|
20
|
-
self.set_log()
|
21
|
-
|
22
|
-
self._host = host
|
23
|
-
self._port = port
|
24
|
-
self._client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
25
|
-
|
26
|
-
def set_log(self):
|
27
|
-
"""设置日志."""
|
28
|
-
self.file_handler.setFormatter(logging.Formatter(self.LOG_FORMAT))
|
29
|
-
self.file_handler.setLevel(logging.INFO)
|
30
|
-
self.logger.addHandler(self.file_handler)
|
31
|
-
if sys.version_info.minor == 11:
|
32
|
-
logging.basicConfig(level=logging.INFO, encoding="UTF-8", format=self.LOG_FORMAT)
|
33
|
-
else:
|
34
|
-
console_handler = logging.StreamHandler()
|
35
|
-
console_handler.setFormatter(logging.Formatter(self.LOG_FORMAT))
|
36
|
-
console_handler.setLevel(logging.INFO)
|
37
|
-
self.logger.addHandler(console_handler)
|
38
|
-
self.logger.setLevel(logging.INFO)
|
39
|
-
|
40
|
-
@property
|
41
|
-
def file_handler(self):
|
42
|
-
"""保存日志的日志处理器."""
|
43
|
-
if self._file_handler is None:
|
44
|
-
log_dir = f"{os.getcwd()}/log"
|
45
|
-
os.makedirs(log_dir, exist_ok=True)
|
46
|
-
file_name = f"{log_dir}/{datetime.datetime.now().strftime('%Y-%m-%d')}_{os.path.basename(os.getcwd())}.log"
|
47
|
-
self._file_handler = TimedRotatingFileHandler(
|
48
|
-
file_name, when="D", interval=1, backupCount=10, encoding="UTF-8"
|
49
|
-
)
|
50
|
-
return self._file_handler
|
51
|
-
|
52
|
-
@property
|
53
|
-
def logger(self):
|
54
|
-
"""日志器."""
|
55
|
-
return self._logger
|
56
|
-
|
57
|
-
@property
|
58
|
-
def host(self):
|
59
|
-
"""服务端ip."""
|
60
|
-
return self._host
|
61
|
-
|
62
|
-
@host.setter
|
63
|
-
def host(self, host):
|
64
|
-
"""设置连接的服务端ip."""
|
65
|
-
self._host = host
|
66
|
-
|
67
|
-
@property
|
68
|
-
def port(self):
|
69
|
-
"""服务端端口号."""
|
70
|
-
return self._port
|
71
|
-
|
72
|
-
@port.setter
|
73
|
-
def port(self, port):
|
74
|
-
"""设置要连接的服务端端口号."""
|
75
|
-
self._port = port
|
76
|
-
|
77
|
-
@property
|
78
|
-
def client(self):
|
79
|
-
"""客户端socket实例."""
|
80
|
-
return self._client
|
81
|
-
|
82
|
-
@client.setter
|
83
|
-
def client(self, client: socket):
|
84
|
-
"""设置客户端socket实例."""
|
85
|
-
self._client = client
|
86
|
-
|
87
|
-
def client_open(self):
|
88
|
-
"""连接服务端."""
|
89
|
-
self.client.connect((self.host, self.port))
|
90
|
-
self._logger.info("*** 和服务端连接成功 ***")
|
91
|
-
|
92
|
-
def client_close(self):
|
93
|
-
"""关闭客户端连接."""
|
94
|
-
self.client.close()
|
95
|
-
self._logger.warning("*** 客户端关闭连接 ***")
|
96
|
-
|
97
|
-
def client_send(self, message: Union[str, bytes]):
|
98
|
-
"""客户端发送数据."""
|
99
|
-
if isinstance(message, str):
|
100
|
-
message = message.encode("UTF-8")
|
101
|
-
self.client.sendall(message)
|
102
|
-
self._logger.info("*** 客户端发送数据 *** -> data: %s", message[:129:])
|
103
|
-
|
104
|
-
def client_receive(self):
|
105
|
-
"""客户端接收数据."""
|
106
|
-
try:
|
107
|
-
while True:
|
108
|
-
data = self.client.recv(1024)
|
109
|
-
if not data:
|
110
|
-
break
|
111
|
-
str_data = data.decode("utf-8")
|
112
|
-
self._logger.info("*** 客户端接收到服务端数据 *** -> data: %s", str_data)
|
113
|
-
self.operations()
|
114
|
-
except Exception as e: # pylint: disable=W0718
|
115
|
-
self._logger.warning("*** 出现异常 *** -> 异常信息: %s", str(e))
|
116
|
-
finally:
|
117
|
-
self.client.close()
|
118
|
-
|
119
|
-
def operations(self):
|
120
|
-
"""根据服务端发过来的数据进行的操作"""
|
121
|
-
|
122
|
-
def run_receive_thread(self):
|
123
|
-
"""启动客户端线程, 实时监听服务端发来的数据."""
|
124
|
-
thread = threading.Thread(target=self.client_receive, daemon=False)
|
125
|
-
thread.start()
|
@@ -1,133 +0,0 @@
|
|
1
|
-
"""异步socket."""
|
2
|
-
import asyncio
|
3
|
-
import datetime
|
4
|
-
import logging
|
5
|
-
import os
|
6
|
-
import socket
|
7
|
-
import sys
|
8
|
-
from asyncio import AbstractEventLoop
|
9
|
-
from logging.handlers import TimedRotatingFileHandler
|
10
|
-
from typing import Union
|
11
|
-
|
12
|
-
|
13
|
-
# pylint: disable=R0801, disable=R0902
|
14
|
-
class CygSocketServerAsyncio:
|
15
|
-
"""异步socket class."""
|
16
|
-
LOG_FORMAT = "%(asctime)s - %(levelname)s - %(module)s:%(lineno)d - %(message)s"
|
17
|
-
|
18
|
-
clients = {} # 保存已连接的client
|
19
|
-
tasks = {}
|
20
|
-
loop: AbstractEventLoop = None
|
21
|
-
|
22
|
-
def __init__(self, address="127.0.0.1", port=8000, key_value_split=b"-_-", end_identifier=b"@_@"):
|
23
|
-
self._address = address
|
24
|
-
self._port = port
|
25
|
-
self._key_value_split = key_value_split
|
26
|
-
self._end_identifier = end_identifier
|
27
|
-
self._logger = logging.getLogger(f"{self.__module__}.{self.__class__.__name__}")
|
28
|
-
self._file_handler = None
|
29
|
-
self.set_log()
|
30
|
-
self.queue = asyncio.Queue()
|
31
|
-
|
32
|
-
def set_log(self):
|
33
|
-
"""设置日志."""
|
34
|
-
self.file_handler.setFormatter(logging.Formatter(self.LOG_FORMAT))
|
35
|
-
self.file_handler.setLevel(logging.INFO)
|
36
|
-
self.logger.addHandler(self.file_handler)
|
37
|
-
if sys.version_info.minor == 11:
|
38
|
-
logging.basicConfig(level=logging.INFO, encoding="UTF-8", format=self.LOG_FORMAT)
|
39
|
-
else:
|
40
|
-
console_handler = logging.StreamHandler()
|
41
|
-
console_handler.setFormatter(logging.Formatter(self.LOG_FORMAT))
|
42
|
-
console_handler.setLevel(logging.INFO)
|
43
|
-
self.logger.addHandler(console_handler)
|
44
|
-
self.logger.setLevel(logging.INFO)
|
45
|
-
|
46
|
-
@property
|
47
|
-
def file_handler(self):
|
48
|
-
"""保存日志的日志器."""
|
49
|
-
if self._file_handler is None:
|
50
|
-
log_dir = f"{os.getcwd()}/log"
|
51
|
-
os.makedirs(log_dir, exist_ok=True)
|
52
|
-
file_name = f"{log_dir}/{datetime.datetime.now().strftime('%Y-%m-%d')}_{os.path.basename(os.getcwd())}.log"
|
53
|
-
self._file_handler = TimedRotatingFileHandler(
|
54
|
-
file_name, when="D", interval=1, backupCount=10, encoding="UTF-8"
|
55
|
-
)
|
56
|
-
return self._file_handler
|
57
|
-
|
58
|
-
@property
|
59
|
-
def logger(self):
|
60
|
-
"""日志实例."""
|
61
|
-
return self._logger
|
62
|
-
|
63
|
-
async def consumer(self, operation_func: callable):
|
64
|
-
"""获取队列里客户端发来的数据进行处理.
|
65
|
-
|
66
|
-
Args:
|
67
|
-
operation_func: 处理函数.
|
68
|
-
"""
|
69
|
-
while True:
|
70
|
-
while self.queue.qsize() != 0:
|
71
|
-
data = await self.queue.get()
|
72
|
-
operation_func(data)
|
73
|
-
self.queue.task_done()
|
74
|
-
|
75
|
-
async def socket_send(self, client_connection, data: Union[bytes, str]):
|
76
|
-
"""发送数据给客户端."""
|
77
|
-
if isinstance(data, str):
|
78
|
-
data = data.encode("UTF-8")
|
79
|
-
if client_connection:
|
80
|
-
client_ip = client_connection.getpeername()
|
81
|
-
await self.loop.sock_sendall(client_connection, data)
|
82
|
-
self._logger.info("*** 发送 *** --> %s 发送成功, %s", client_ip, data)
|
83
|
-
else:
|
84
|
-
self._logger.info("*** 发送 *** --> 发送失败, %s, 未连接", data)
|
85
|
-
|
86
|
-
async def receive_send(self, client_connection: socket.socket):
|
87
|
-
"""接收发送数据."""
|
88
|
-
client_ip = client_connection.getpeername()[0] # 获取连接客户端的ip
|
89
|
-
self._logger.info("%s 处理 %s 客户端的任务开始 %s", "-" * 30, client_ip, "-" * 30)
|
90
|
-
buffer_byte = b""
|
91
|
-
try:
|
92
|
-
while data_byte := await self.loop.sock_recv(client_connection, 1024 * 1024):
|
93
|
-
buffer_byte += data_byte
|
94
|
-
if self._end_identifier in buffer_byte:
|
95
|
-
await self.socket_send(client_connection, b"^_^")
|
96
|
-
one_message_byte, remaining = buffer_byte.split(self._end_identifier, 1)
|
97
|
-
buffer_byte = remaining
|
98
|
-
keys, datas = one_message_byte.split(self._key_value_split, 1)
|
99
|
-
await self.queue.put({keys: datas})
|
100
|
-
self._logger.info("*** 将一条完整消息放入队列 ***")
|
101
|
-
self._logger.info("keys: %s", keys)
|
102
|
-
self._logger.info("datas: %s", datas[:129:])
|
103
|
-
except Exception as e: # pylint: disable=W0718
|
104
|
-
self._logger.warning("*** 通讯出现异常 *** --> 异常信息是: %s", e)
|
105
|
-
finally:
|
106
|
-
self.clients.pop(client_ip)
|
107
|
-
self.tasks.get(client_ip).cancel()
|
108
|
-
self._logger.warning("*** 下位机断开 *** --> %s, 断开了", client_ip)
|
109
|
-
self._logger.info("%s 处理 %s 客户端的任务结束 %s", "-" * 30, client_ip, "-" * 30)
|
110
|
-
client_connection.close()
|
111
|
-
|
112
|
-
async def listen_for_connection(self, socket_server: socket):
|
113
|
-
"""异步监听连接."""
|
114
|
-
self._logger.info("*** 服务端已启动 *** --> %s 等待客户端连接", socket_server.getsockname())
|
115
|
-
|
116
|
-
while True:
|
117
|
-
self.loop = asyncio.get_running_loop()
|
118
|
-
client_connection, address = await self.loop.sock_accept(socket_server)
|
119
|
-
self._logger.warning("*** 下位机连接 *** --> %s, 连接了", address)
|
120
|
-
client_connection.setblocking(False)
|
121
|
-
await self.socket_send(client_connection, "^_^")
|
122
|
-
self.clients.update({address[0]: client_connection})
|
123
|
-
self.tasks.update({address[0]: self.loop.create_task(self.receive_send(client_connection))})
|
124
|
-
self._logger.warning("*** 创建了处理 %s 客户端的任务 ***", address)
|
125
|
-
|
126
|
-
async def run_socket_server(self):
|
127
|
-
"""运行socket服务, 并监听客户端连接."""
|
128
|
-
socket_server = socket.socket()
|
129
|
-
socket_server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
130
|
-
socket_server.setblocking(False)
|
131
|
-
socket_server.bind((self._address, self._port))
|
132
|
-
socket_server.listen()
|
133
|
-
await self.listen_for_connection(socket_server)
|
File without changes
|
File without changes
|
File without changes
|