基于Netty的Android长连接实现

本文介绍了基于Netty实现Android长连接的详细过程,包括协议确定、加解密、封装解封装、发包收包对应、心跳机制、网络重连及超时重发策略。重点讲解了协议结构、RSA非对称加密与AES对称加密的运用,以及如何通过序列号sn确保通信的对应性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0. 传送门

https://github.com/jeanpeng/Netty4Android.git (欢迎star)

1. 协议的确定

  • 协议头——4字节,标识协议体的长度
  • 协议体——包括4字节扩展信息+传参,其中扩展信息里包括协议加密类型,传参为key,value键值对类型的数据,数据格式为4字节key长度+key+4字节value长度+value

2.协议加解密

  • 客户端随机生成16位密钥,通过RSA非对称加密方式将密钥同步给服务器
  • 密钥同步后,使用该密钥通过AES对称加密的方式对协议进行加密,然后进行数据传输

3.协议封装和解封装

package com.**.nettylib.netty.codec;

import com.**.nettylib.constant.NetworkConfig;
import com.**.nettylib.netty.Request;
import com.**.nettylib.netty.util.AESUtils;
import com.**.nettylib.netty.util.ExtendInfo;
import com.**.nettylib.netty.util.GZIPUtils;
import com.**.nettylib.netty.util.KeyManager;
import com.**.nettylib.netty.util.MsgEncryptType;
import com.**.nettylib.netty.util.ProtocolUtil;
import com.**.nettylib.netty.util.RSAUtils;

import java.io.ByteArrayOutputStream;
import java.util.Map;
import java.util.Set;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * Created by james on 2018/7/30.
 * 加密协议组包,支持处理粘包和半包
 */
public class MessageEncryptEncoder extends MessageToByteEncoder<Request> {

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, Request request, ByteBuf byteBuf) throws Exception {
        byteBuf.writeBytes(encodeResponse(request));
    }

    public byte[] encodeResponse(Request request) {
        try {
            Map<String, String> properties = request.toMap();
            Set<Map.Entry<String, String>> propertiesSet = properties.entrySet();
            ByteArrayOutputStream bodyStream = new ByteArrayOutputStream();
            for (Map.Entry<String, String> property : propertiesSet) {
                String propertyName = property.getKey();
                String propertyValue = property.getValue();
                bodyStream.write(ProtocolUtil.stringToByteArray(propertyName, "utf-8"));
                bodyStream.write(ProtocolUtil.stringToByteArray(propertyValue, "utf-8"));
            }
            byte[] bodyBytes = bodyStream.toByteArray();// 数据部分
            bodyStream.close();

            ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
            ExtendInfo ext = request.getExt();
            byte[] extBytes = ext.toExtBytes();
            int msgEncryptType = ext.getMsgEncryptType();
            if (MsgEncryptType.NONO == msgEncryptType) {
                // do noting
            } else if (MsgEncryptType.RSA == msgEncryptType) {
                bodyBytes = doEncodeOfRSA(bodyBytes);
            } else if (MsgEncryptType.AES == msgEncryptType) {
                bodyBytes = doEncodeOfAES(bodyBytes);
            }
            responseStream.write(ProtocolUtil.intToByteArray(bodyBytes.length + extBytes.length));
            responseStream.write(extBytes);
            responseStream.write(bodyBytes);
            byte[] responseBytes = responseStream.toByteArray();// 整个响应包
            responseStream.close();
            return responseBytes;
        } catch (Exception e) {
            return null;
        }
    }

    private byte[] doEncodeOfRSA(byte[] bodyBytes) {
        // 先压缩,再加密
        return RSAUtils.publicEncrypt(GZIPUtils.compress(bodyBytes), NetworkConfig.RSA_PUBLIC_KEY);
    }

    private byte[] doEncodeOfAES(byte[] bodyBytes) {
        String password = KeyManager.aesKey;
        // 先压缩,再加密
        return AESUtils.encrypt(GZIPUtils.compress(bodyBytes), password);
    }
}

package com.**.nettylib.netty.codec;

import com.**.nettylib.netty.util.AESUtils;
import com.**.nettylib.netty.util.ExtendInfo;
import com.**.nettylib.netty.util.GZIPUtils;
import com.**.nettylib.netty.util.KeyManager;
import com.**.nettylib.netty.util.MsgEncryptType;
import com.**.nettylib.netty.util.ProtocolUtil;

import java.io.ByteArrayInputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDeco
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值