一个Socket通信案例

本文通过一个具体的Socket通信案例,分析了原有代码存在的问题,即大函数导致的高耦合、低可维护性和扩展性差。为了解决这些问题,提出了通过消息池、接收指令管理和发送指令管理三个方面进行重构。消息池利用对象池技术提高效率和减少内存开销,接收指令管理通过ICommand和CmdDispatcher实现解耦和扩展性,而发送指令管理则按照相同思路处理。
摘要由CSDN通过智能技术生成

1. 概述

公司产品客户端需要通过socket和C++后台交互,大概是这么一个流程:

  1. 通过配置文件,解析服务器的地址和端口;
  2. 打开socket通道,建立和服务器的长链接;
  3. 和服务器通信,发送指令和接收指令等;
  4. 应用退出,关闭连接。

问题在这里,和服务器通信,拿到一个完整的消息后,通过解析指令的参数,进行不同的处理,现有的代码,把所有的逻辑代码大部分写在了一个switch代码块里面,一个函数七八百行,中间参杂了各种UI的操作整个人都感觉不好了…

2.问题分析

分析这个问题,其实和以前做过的蓝牙通信是一样的,就是服务端发送一个数据过来,如byte[](也可能是直接解析byte[]得到一个json字符串)。客户端通过socket接收,先解析判断,等接收一个完数据,整再发送一个消息给客户端上层,并把数据带过去。上层拿到完整的数据,先根据协议,解析出是具体哪个指令,参数等。然后根据具体指令,执行对应的业务。这就是一个套路,对于socket,蓝牙是一个道理的,其实就是对消息的一个分发处理。
现有代码的实现是把所有代码放在一个switch代码块中(其实连dosomething都没有):

int cmd;     // 这个就是后台发过来的具体哪个指令的参数
Message msg; // 指令带的参数
switch(cmd) {
   
    case 1: 
        dosomething1(msg);
        break;
    case 2: 
        dosomething2(msg);
        break;
    case 3: 
        dosomething3(msg);
        break;
    ...
}

这种写法,也不是不行,能运行,当时也就在业务不多的时候适用,如果后台定义的指令几十上百个呢?所有的业务全部耦合在一起,如果需求改动,说不定就牵一发而动全身了,最重要的一点就是,这种没有设计的代码,一个函数长达七八百行,难看懂难维护。

3.如何解决

这种大函数的做法可以肯定是不对的,第一,耦合性强,所有业务代码和功能代码揉在一起;第二,可维护性太低,大函数,业务复杂,调试困难,除了写这段代码的人熟悉,一旦换人接手,就是一个大坑;第三,可扩展性不强,如果需求改动或者增加一个指令,就得改这一段代码。要解决这一类问题,就得从降低耦合性,提高可维护性和可扩展性三个方向着手。所以,如何做呢?通过抽象,将消息接收和消息发送分离开来,先定义基类,再每个命令定义一个类,最后写一个统一管理的类。为了复用,可以使用一个消息池技术,如此达到接耦,提高可扩展和可维护性。简单分解为三个部分:

  1. 消息池
  2. 接收服务器指令管理
  3. 本地发送指令管理

3.1 消息池

这个是从一篇写自定义消息队列的文章中看到而得到启发(对象池),后台发过来的消息,其实是一个高度抽象的协议(protobuf,json等),解析过后得到一般格式固定,假设定义为Message。为了提高效率和减少内存开销,可以使用对象池技术进行复用。

Message
public class Message<T> {
   
    int mCmd; // 指令编号
    T data;   // 指令携带的参数
}
MessagePool
public class MessagePool extends ObjectPool<Message> {
   

    private static MessagePool sMsgPool = new Messa
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值