|
本帖最后由 白冥 于 2024-4-29 00:20 编辑
事先说明,代码有点长,可能被吞:
client.py
from client_socket import ClientSocket
from client_thread import ClientThread
class client:
def __init__(self):
self.socket=ClientSocket()
self.thread=ClientThread(self.socket)
self.socket.start()
self.thread.start_thread(
send_thread=self.socket.send,
receive_thread=self.socket.receive,
heartbeat_thread=self.socket.heartbeat
)
if not self.thread.condition:
self.socket.stop()
client_socket.py
import socket import time from config import Config from message import Message class ClientSocket: def __init__(self): self._init_socket() self.id=Config.clientHost self.running=True self.server_disconnected=False def _init_socket(self): self.socket=socket.socket(socket.AF_INET,socket.SOCK_STREAM) self.socket.connect((Config.serverHost,Config.usingPort)) def start(self): self.send(Config.MessageType.inquire,Config.Instruction.please,self.id,Config.serverId) def stop(self): self.running=False self.socket.close() def send(self,type,instruction,sender,addressee,content=''): MESSAGE=Message.dumps(type,instruction,sender,addressee,content) self.socket.sendall(MESSAGE) self.handle_send(MESSAGE) def receive(self): MESSAGE=self.socket.recv(Config.maximumTextLimit).decode() self.handle_receive(MESSAGE) if Message.is_message(MESSAGE) else None def handle_send(self,message): match message['type']: case Config.MessageType.inquire: match message["instruction"]: case Config.Instruction.bye: self.stop() def handle_receive(self,message): DICTIONARY=Message.loads(message) if type(DICTIONARY)==dict: match DICTIONARY['type']: case Config.MessageType.transmit: match DICTIONARY['instruction']: case Config.Instruction.text: print(f'A message from {DICTIONARY['sender']}\n') print('Main body:\n') print(f'{DICTIONARY['content']}\n') case Config.MessageType.detection: match DICTIONARY['instruction']: case Config.Instruction.detect: match DICTIONARY['sender']: case Config.serverId: self.server_disconnected=False case Config.MessageType.inquire: match DICTIONARY['instruction']: case Config.Instruction.bye: print(f'Addressee {DICTIONARY['sender']} stopped communication') case Config.MessageType.respond: match DICTIONARY['instruction']: case Config.Instruction.text: print(f'A message from {DICTIONARY['sender']}\n') print('Main body:\n') print(f'{DICTIONARY['content']}\n') case Config.MessageType.report: match DICTIONARY['sender']: case Config.serverId: match DICTIONARY['instruction']: case Config.Instruction.id: print(f'You has been assigned an ID:{DICTIONARY['content']}') self.sender_id=DICTIONARY['content'] case Config.Instruction.known: print('Reconnecting to the server succeeded.') def heartbeat(self): self.send(Config.MessageType.detection,Config.Instruction.detect,self.id,Config.serverId) self.server_disconnected=True time.sleep(Config.heartbeatRate) if self.server_disconnected: print('We temporarily lost contact with the server.') if not self.reconnect(): self.stop def reconnect(self,attempt=1): if attempt<=Config.maximumAttemptLimit: try: self.stop() self.running=True self._init_socket() return True except Exception as error: print(f'Failed to reconnect to the server') time.sleep(5) self.reconnect(attempt+1) else: return False
client_thread.py
import threading class ClientThread: def __init__(self,client_socket): self.condition=client_socket.running def loop(self,callback): while self.condition: callback() def start_thread(self,**threads): try: threads_list:list[threading.Thread]=[] for thread,callback in threads.items(): thread=threading.Thread(target=ClientThread.loop,args=(self,callback)) thread.start() threads_list.append(thread) for thread in threads_list: thread.join() except Exception as error: print(f'An error occurs:{error}') self.condition=False
config.py
import configparser CONFIG=configparser.ConfigParser() CONFIG.read('config.ini') class Config: serverHost=CONFIG.get('SERVER','host') clientHost=CONFIG.get('CLIENT','host') usingPort=CONFIG.getint('SERVER','port') serverId=CONFIG.get('SERVER','id') heartbeatRate=CONFIG.getint('CLIENT','heartbeat_rate') maximumAttemptLimit=CONFIG.getint('CLIENT','maximun_attempt_limit') maximumTextLimit=CONFIG.getint('TEXT','maximum_text_limit') class Instruction: text=CONFIG.get('INSTRUCTIONS','send_text') file=CONFIG.get('INSTRUCTIONS','send_file') error=CONFIG.get('INSTRUCTIONS','send_error') bye=CONFIG.get('INSTRUCTIONS','end_communication') please=CONFIG.get('INSTRUCTIONS','request_to_join') id=CONFIG.get('INSTRUCTIONS','allocation_id') call=CONFIG.get('INSTRUCTIONS','request_reconnection') known=CONFIG.get('INSTRUCTIONS','successfull_reconnection') detect=CONFIG.get('INSTRUCTIONS','heartbeat_detection') class MessageType: transmit=CONFIG.get('MESSAGE_TYPES','transmit') detection=CONFIG.get('MESSAGE_TYPES','detection') inquire=CONFIG.get('MESSAGE_TYPES','inquire') respond=CONFIG.get('MESSAGE_TYPES','respond') report=CONFIG.get('MESSAGE_TYPES','report')
message.py
import json class Message: @staticmethod def dumps(msg_type,instruction,sender,addressee,content): DICTIONARY={ "type":msg_type, "instruction":instruction, "sender":sender, "addressee":addressee, "content":content, } return json.dumps(DICTIONARY).encode() @staticmethod def is_message(message): TEMPLATE={"type","instruction","sender","addressee","content"} try: DICTIONARY=json.loads(message) if type(DICTIONARY)==dict: return set(DICTIONARY.keys())==TEMPLATE except json.JSONDecodeError: return False @staticmethod def loads(message): if Message.is_message(message): return json.loads(message)
config.ini
[SERVER]
host=127.0.0.1
port=6363
id=Server
[CLIENT]
host=localhost
heartbeat_rate=10
maximum_attempt_limit=3
[INSTRUCTIONS]
send_text=/text
send_file=/file
send_error=/error
end_communication=/bye
request_to_join=/please
allocation_id=/id
request_reconnection=/call
successfull_reconnection=/known
heartbeat_detection=/detect
[MESSAGE_TYPES]
transmit=transmit
detection=detection
inquire=inquire
respond=respond
report=report
[TEXT]
maximum_text_limit=4096
|
评分
-
查看全部评分
- 白冥
:这段代码是一个简单的Python客户端应用程序,它使用了socket模块来实现TCP连接,以及threading模块来实现多线程通信。这个应用程序似乎用于和一个服务器应用程序通信,它处理接收和发送消息、心跳检测、重连等逻辑。下面是每个文件的大致功能:
client.py:
定义了client类,它初始化了一个ClientSocket对象和一个ClientThread对象。
启动了socket和线程,并在线程中运行发送、接收和心跳检测的函数。
如果线程的条件不满足,则停止socket。
client_socket.py:
定义了ClientSocket类,它负责建立与服务器的连接。
提供了发送、接收消息的方法,以及处理发送和接收消息的逻辑。
实现了心跳检测逻辑,用于检测与服务器的连接是否仍然有效。
提供了重连逻辑,如果检测到服务器断开连接,尝试重新连接。
client_thread.py:
定义了ClientThread类,它负责在单独的线程中运行函数。
提供了启动线程的方法,并等待所有线程完成。
config.py:
从config.ini文件中读取配置信息,如服务器地址、端口、心跳检测速率等。
定义了一些常量,如消息类型、指令等。
message.py:
提供了用于序列化和反序列化消息的方法。
定义了消息格式,包括类型、指令、发送者、接收者和内容。
config.ini:
包含应用程序的配置信息,如服务器地址、端口、心跳检测速率等。
-
|