GameMale
登陆 / 注册 搜索

USERCENTER

SEARCHSITE

搜索

查看: 1074|回复: 28
收起左侧

[技术交流] 基于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 回复
    • 我也说一句

    回复

    使用道具 举报

    百相千面-晦永远的克叔業火死鬥实现梦想官复原职虚空之海的鲸Zootopia幸运女神的微笑『逆境中的幸运女神』御医神兔

      回复

      使用道具 举报

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

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

        使用道具 举报

        无瑕的回忆朴素的誓言Futūrum(未来)果体76文森特‧瓦伦丁永远的克叔里昂‧S‧甘乃迪传说的黑道-桐生一马

          回复

          使用道具 举报

          希尔瓦娜斯·风行者麦迪文(Medivh)阿尔萨斯‧米奈希尔创生之柱卡德加(Khadgar)安杜因·乌瑞恩我的天使夏日柯基幸福的小阿尔吃饱金币的Doge

            回复

            使用道具 举报

            朴素的誓言无瑕的回忆『逆境中的幸运女神』幸运女神的微笑GHOST瓮中能言蛙近地夜航

              回复

              使用道具 举报

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

                回复

                使用道具 举报

                我的天使GM吸血伯爵吃饱金币的Doge阿拉喵?神灯和你一起飞行的皮卡丘小小舞台永浴爱河

                  回复

                  使用道具 举报

                  咆哮诅咒敖蜃星黑暗交易阿怪GHOST吃饱金币的Doge秘密空瓶裸体克里斯【圣诞限定】心心念念小雪人【夏日限定】夏日的泰凯斯

                    回复

                    使用道具 举报

                    男巫之歌【夏日限定】夏日的泰凯斯裸体克里斯瓮中能言蛙果体76吸血魔蝠内森·德雷克生金蛋的鹅永远的克叔亚瑟‧摩根

                      回复

                      使用道具 举报

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

                        回复

                        使用道具 举报

                        20x43 隐形➀吃饱金币的Doge冒险用指南针金牌矿工小小安全帽小小舞台阿拉喵?神灯图腾饼干『梦旅存根』

                          回复

                          使用道具 举报

                          实现梦想業火死鬥魔法不朽·传奇不熄卡洛斯·奥利维拉白野威十年一梦官复原职男巫之歌永浴爱河虚空之海的鲸

                            回复

                            使用道具 举报

                            内森·德雷克業火死鬥诺克提斯·路西斯·伽拉姆BIG BOSS克莱夫・罗兹菲尔德岛田半藏性感男神GM莱因哈特·威尔海姆

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

                              使用道具 举报

                              缘起星空虚空之海的鲸

                                回复

                                使用道具 举报

                                极·龙の意『灰域来音』阿怪纯真护剑不灭狂雷 『先知灵药:真视』泰比里厄斯永浴爱河风物长宜

                                  回复

                                  使用道具 举报

                                  男巫之歌内森·德雷克『私有海域』裸体克里斯双向圣杯:焕然意志极·龙の意【圣诞限定】心心念念小雪人小小舞台御医神兔永浴爱河

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

                                    使用道具 举报

                                    『户口本: Lv7+』十年一梦岛田源氏杰森‧斯坦森Forever Titanic虚空之海的鲸缘起星空美恐:新的开始雄躯的昇格『终点站:极地』

                                      回复

                                      使用道具 举报

                                      虚空之海的鲸『私有海域』『钜鲸』『星河碎片』『召唤好运的角笛』『交钥匙了!』『矩阵谜钥Ⓖ』十周年扭蛋 - 红『落樱缤纷』红心玉

                                        回复

                                        使用道具 举报

                                          回复

                                          使用道具 举报

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

                                          本版积分规则

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

                                          GMT+8, 2024-12-22 14:11 , Processed in 0.204169 second(s), 142 queries , Redis On.

                                          Copyright © 2013-2024 GameMale

                                          All Rights Reserved.

                                          快速回复 返回列表