zoukankan      html  css  js  c++  java
  • IMLite轻量级即时通信工具开发指南

    花了一周时间开发了一个简单的即时通信工具,勉强算是程序原型。现在我把开发流程和一些个人的想法记录下来。本文首先介绍程序架构和通信接口,之后会聚焦到服务器的信号槽设计原则,接下来将解释有关TCP通信的粘包问题和解决方案,最后一个部分是一些改进建议。

    源码下载: https://gitee.com/learnhow/imlite

    程序架构图例:

    一、架构方案介绍

    主程序(MainWindow)启动服务器(TcpServer),在收到客户端的连接请求之后会开启一个线程并创建子连接(TcpSocket)。目前支持的消息类型有三种,分别为:Message——由客户端发起的端到端消息或直接由服务器发起的广播消息,这是即时通信最基础的通信要求。MessageConnCallback——由服务器向新连接的终端发起的socketID反向注册信息,目的是告知客户端本次连接在服务器端生成的socketID。MessageConnecter——由服务器向所有终端发布的一条广播,通知所有终端其他的终端socketID和客户端自定义的nickname,这是实现端到端通信的基础。

    端到端通信的原理实际上是由客户端发送一条携带了接收方socketID的信息。服务器在收到后会解析并进行转发。

    为了让多种消息类型能够统一,程序提供了MessageInterface接口和TcpSocketData对象。所有的消息类型都必须实现MessageInterface接口,并且在发送端和接收端都必须通过TcpSocketData来注册消息类型包括进行序列化和反序列化。

    NetPacket提供了消息打包和解包方法。为发送的数据包加上一个字符串作为包尾,并且在接收端可以根据包尾来解包并分割为原始报文。更详细的信息将在第三节介绍。

    SQLiteService实现了一种简单的数据保存方法,由于程序开发的重点不在于此,并没有做专门设计。二次开发中应该会重新设计,这里一带而过。

    二、通信机制介绍

    本例中所有对象的通信都采用信号槽,信号槽是Qt提供的一种消息流转机制。在命名规则上,程序按照Qt的命名方案:槽的命名使用动词一般现在时,信号命名使用动词过去时。并且以“谁创建谁连接”的原则编写,例如:TcpServer负责创建所有的子连接TcpSocket,因此与它的信号槽连接都会放在TcpServer中实现。

    接下来以客户端向服务器端发起连接请求为例做简单介绍。服务器(TcpServer)通过incomingConnection(qintptr)方法产生socketID,立刻通过子连接向终端发送connectionCallback信号,接着会发送广播向终端通知有新的连接加入,最后还会向UI层发送一个与显示有关的信号(程序中表现为在QWidgetList中增加一个Item)。

    // 当有新的终端连接请求时被调用
    void TcpServer::incomingConnection(qintptr handle)
    {
        ...
    
        clientStatusConnect(QString("%1").arg(handle));
    }
    
    void TcpServer::clientStatusConnect(QString socketDescriptor)
    {
    
        socketnicknamemap.insert(socketDescriptor, "Guest");
        // 向终端反向注册handle
        MessageConnCallback callback; 
        callback.setSocketDescriptor(socketDescriptor);
        emit connectionCallback(callback); ①
    
        MessageConnecter msgConn;
        msgConn.setConnectors(socketnicknamemap);
        emit terminalsPublished(msgConn); ②
    
        // 反馈信号至UI:增加终端
        emit clientStatusTriggered(socketDescriptor, 1);
    }

    其它的代码就不一一解释了。

    三、Tcp粘包和解决方案

    观察上面的源码片段,当有新连接产生后,服务器会“同时”向终端发送两条数据(注:①②)。客户端的void dataRecv()方法会调用QByteArray buff = tcpSocket->readAll()读取数据,这时有极大的几率发生“粘包”——服务器发送的两条报文A、B,客户端以A+B作为一条报文读取出来。我的解决方案是在发送端为每段报文增加一个字符串(CF07D)作为结束标志,在接收端就以此标志对报文分割。

    QByteArray NetPacket::package(const QByteArray &data)
    {
        QByteArray wrap(data);
        wrap += splite;
        return wrap;
    }
    
    QList<QByteArray> NetPacket::unpackage(const QByteArray &wrap)
    {
        QList<QByteArray> bufflist;
        int pos = 0;
        int prev = 0;
        while((pos = wrap.indexOf(splite, pos)) != -1) {
            QByteArray part = wrap.mid(prev, pos);
            bufflist.push_back(part);
            pos += splite.length();
            prev = pos;
        }
        return bufflist;
    }

    四、问题及改进建议

    (1)信号槽是一个好东西,但是不能滥用:程序中所有对象的数据流转都是通过信号槽机制。不可否认这样做似乎减少了模块耦合,但是增加了维护的难度。并且看上去也显得“乱糟糟”的。如果一条数据同时需要经过多个对象处理,就必须为此设计多个信号槽。

    (2)把消息分开传输:服务器的自连接与客户端之间只使用了一个socket端口通信(8361),这样在接收端就必须为不同的消息类型设计不同的type值。更加合理的做法是让客户端与服务器同时使用多个端口进行通信,既有利于需求扩展又不至于让接收端的方法无限膨胀。

    查看全文
  • 相关阅读:
    Mysql执行顺序
    读取资源文件ResourceUtils
    军规(一)
    Spring声明式事务@Transactional 详解,事务隔离级别和传播行为
    linux crontab
    es _cat API
    elastic search 常用查询
    elastic search 重要的系统配置
    cerebro 配置
    Ubuntu18.04 搭建zookeeper单机版集群
  • 原文地址:https://www.cnblogs.com/learnhow/p/8641965.html
  • 最新文章
  • MySQL基本命令
    MySQL安装
    android:screenOrientation属性
    Android代码命名规范
    使用element-ui 组件动态合并table的行/列(第二次修改)
    使用yarn搭建vue项目
    服务器搭建node环境
    实现滚动时页面伸缩效果
    Vue培训项目总结
    React学习笔记一
  • 热门文章
  • Vue知识分享一
    js计算每个月的总天数
    phaser小游戏框架学习(二)
    phaser小游戏框架学习中的屏幕适配
    maven archetype 构建项目
    idea破解
    IDEA编译时出现 Information:java: javacTask: 源发行版 1.8 需要目标发行版 1.8
    线上服务器CPU占用率高如何排查定位
    idea看代码
    mysql慢日志的配置与查询
Copyright © 2011-2022 走看看

深圳SEO优化公司巴中网站优化按天收费价格宜昌网站搜索优化公司东营网站排名优化报价烟台网站seo优化北海网站关键词优化多少钱上饶外贸网站设计公司通辽SEO按天收费关键词排名公司河池SEO按效果付费价格咸宁网站排名优化公司宝安外贸网站建设景德镇网站优化按天收费推荐南宁网站优化按天收费推荐周口网站改版公司济南网站制作设计哪家好漳州网站关键词优化陇南网页制作哪家好滨州网站优化价格大理百度竞价多少钱大鹏百度竞价哪家好吉祥百度竞价包年推广报价烟台百度网站优化报价霍邱seo网站推广公司滁州如何制作网站报价承德百度网站优化排名公司长葛百搜标王推荐和田建网站推荐贵港seo排名报价黔西南SEO按天扣费公司宿迁模板推广推荐歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化