GameMale
登陆 / 注册 搜索

USERCENTER

SEARCHSITE

搜索

查看: 603|回复: 27
收起左侧

[技术交流] 基于python的多线程聊天室的客户端部分(包括ini配置文件)

[复制链接] |关注本帖
     楼主| 白冥 发表于 2024-4-28 00:50:29 | 显示全部楼层 |阅读模式 |取消关注该作者的回复
    本帖最后由 白冥 于 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



    评分

    参与人数 1血液 +2 追随 +1 收起 理由
    大臣 + 2 + 1

    查看全部评分

      收起(1)
    • 白冥 白冥 :这段代码是一个简单的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:
      包含应用程序的配置信息,如服务器地址、端口、心跳检测速率等。
      2024-04-29 00:29 回复
    • 我也说一句

    回复

    使用道具 举报

    官复原职实现梦想吃饱金币的Doge和你一起飞行的皮卡丘崩朽之青铜龙王虚空之海的鲸永远的克叔『召唤好运的角笛』『流星赶月:宙刃』重建熊屋

      回复

      使用道具 举报

      不曾寄出的信件『随时随地开启!』漂洋小船『随时随地开启!』冒险用指南针破损的旧书丛林的鸟飞走了人鱼之泪雪王的心脏幽灵竹筒

        好专业的感觉呀,多线程聊天室是用于聊天用的代码吗?
        回复

        使用道具 举报

        金刚狼肥皂结晶火鹰幼崽刺杀者匕首野兽之子蒂法·洛克哈特寂静岭三角头牧羊人赛博朋克2077收到情书

          回复

          使用道具 举报

          至情至性One Ring阿尔萨斯‧米奈希尔吃饱金币的Doge威克多尔·克鲁姆我的冶金打火机遍江云霞王座的毗邻希尔瓦娜斯·风行者史莱哲林

            回复

            使用道具 举报

            幽浮起司煲卡勒罗斯辉石头罩结晶火鹰幼崽禽兽扒手凶猛的鳄鱼瓮中能言蛙赫敏·格兰杰森林羊男

              回复

              使用道具 举报

              诺克提斯·路西斯·伽拉姆業火死鬥钢铁侠永远的克叔极·龙の意死灵之书卡利亚权杖虚空之海的鲸史莱姆牧场男巫之歌

                回复

                使用道具 举报

                我的天使阿拉喵?神灯

                  回复

                  使用道具 举报

                  幽灵竹筒龙鳞石和你一起飞行的皮卡丘【夏日限定】夏日的泰凯斯雪王的心脏肥皂苏醒的格罗姆吃饱金币的Doge破损的旧书杰西·麦克雷

                    回复

                    使用道具 举报

                    没有梦想的咸鱼裸体克里斯瓮中能言蛙【夏日限定】夏日的泰凯斯夜魔护符闪耀的魔仙棒【圣诞限定】心心念念小雪人史莱姆牧场

                      回复

                      使用道具 举报

                      亚索月影狼晓月终焉旅行骰子!卡利亚权杖

                        回复

                        使用道具 举报

                        『落樱缤纷』火柴 - Gamemale灵魂之椅吃饱金币的Doge夏日柯基阿拉喵?神灯小小舞台40x43 隐形➁

                          回复

                          使用道具 举报

                          崩朽之青铜龙王虚空之海的鲸实现梦想官复原职永浴爱河白野威業火死鬥十年一梦男巫之歌

                            回复

                            使用道具 举报

                            莱因哈特·威尔海姆Dante卢西亚诺‧科斯塔暮狼归来守护者三角头肥皂『流星赶月』亚索克莱夫・罗兹菲尔德崩朽之青铜龙王

                              koh 发表于 2024-4-28 07:39:38 | 显示全部楼层 |取消关注该作者的回复
                              回复

                              使用道具 举报

                              缘起星空虚空之海的鲸

                                回复

                                使用道具 举报

                                幽浮起司煲伪造的红石雪王的心脏小小舞台 『先知灵药:真视』永浴爱河泰比里厄斯风物长宜

                                  回复

                                  使用道具 举报

                                  男巫之歌内森·德雷克『私有海域』亚索双向圣杯:焕然意志极·龙の意【圣诞限定】心心念念小雪人小小舞台肉垫手套業火死鬥

                                    懂了,下次写什么小玩意要嵌聊天的时候可以参考了
                                    作为简易的就是足够简易才好,这个就很不错
                                    回复

                                    使用道具 举报

                                    双贤辉石头罩『流星赶月:宙刃』肥皂结晶火鹰幼崽卢西亚诺‧科斯塔蒂法·洛克哈特刺杀者匕首亚索【夏日限定】夏日的泰凯斯『终点站:极地』

                                      回复

                                      使用道具 举报

                                      『钜鲸』『私有海域』『召唤好运的角笛』『流星赶月:宙刃』『星河碎片』『伊黎丝的赞词』『落樱缤纷』『交钥匙了!』『矩阵谜钥Ⓖ』虚空之海的鲸

                                        回复

                                        使用道具 举报

                                        炼金之心『住在GM村』神秘商店贵宾卡黑暗交易

                                          回复

                                          使用道具 举报

                                          您需要登录后才可以回帖 登录 | 立即注册

                                          本版积分规则

                                          文字版|手机版|小黑屋|GameMale

                                          GMT+8, 2024-5-10 14:40 , Processed in 0.098270 second(s), 143 queries , Redis On.

                                          Copyright © 2013-2024 GameMale

                                          All Rights Reserved.

                                          快速回复 返回列表