Coder Social home page Coder Social logo

androidsocketclient's Introduction

AndroidSocketClient

socket client server简易封装

Import

JitPack

Add it in your project's build.gradle at the end of repositories:

repositories {
  // ...
  maven { url "https://jitpack.io" }
}

Step 2. Add the dependency in the form

dependencies {
  compile 'com.github.vilyever:AndroidSocketClient:3.0.3'
}

Updates

  • 3.0.3

提升readByLength按长度读取的速度 [issue #26](/../../issues/26)
  • 3.0.2

修复初次连接失败时,因CountDownTimer导致崩溃的问题 [issue #24](/../../issues/24)
  • 3.0.1

修复包头验证bug,by zzdwuliang
增加地址检测的详细log
  • 3.0.0

支持ReadToData和ReadToLength自动读取以下两种结构
常见包结构1:【包头(可选)】【正文】【包尾】
常见包结构2:【包头(可选)】【余下包长度(正文加包尾长度)(此部分也可做包头)(此部分长度固定)】【正文】【包尾(可选)】

Usage

app模块下包含简单的使用demo

请一定设置读取策略socketClient.getSocketPacketHelper().setReadStrategy();

远程端连接信息配置

    socketClient.getAddress().setRemoteIP(IPUtil.getLocalIPAddress(true)); // 远程端IP地址
    socketClient.getAddress().setRemotePort("21998"); // 远程端端口号
    socketClient.getAddress().setConnectionTimeout(15 * 1000); // 连接超时时长,单位毫秒

默认String编码配置

    /**
     * 设置自动转换String类型到byte[]类型的编码
     * 如未设置(默认为null),将不能使用{@link SocketClient#sendString(String)}发送消息
     * 如设置为非null(如UTF-8),在接受消息时会自动尝试在接收线程(非主线程)将接收的byte[]数据依照编码转换为String,在{@link SocketResponsePacket#getMessage()}读取
     */
    socketClient.setCharsetName(CharsetUtil.UTF_8); // 设置编码为UTF-8

固定心跳包配置

    /**
     * 设置自动发送的心跳包信息
     */
    socketClient.getHeartBeatHelper().setDefaultSendData(CharsetUtil.stringToData("HeartBeat", CharsetUtil.UTF_8));

    /**
     * 设置远程端发送到本地的心跳包信息内容,用于判断接收到的数据包是否是心跳包
     * 通过{@link SocketResponsePacket#isHeartBeat()} 查看数据包是否是心跳包
     */
    socketClient.getHeartBeatHelper().setDefaultReceiveData(CharsetUtil.stringToData("HeartBeat", CharsetUtil.UTF_8));

    socketClient.getHeartBeatHelper().setHeartBeatInterval(10 * 1000); // 设置自动发送心跳包的间隔时长,单位毫秒
    socketClient.getHeartBeatHelper().setSendHeartBeatEnabled(true); // 设置允许自动发送心跳包,此值默认为false

动态变化心跳包配置

    /**
     * 设置自动发送的心跳包信息
     * 此信息动态生成
     *
     * 每次发送心跳包时自动调用
     */
    socketClient.getHeartBeatHelper().setSendDataBuilder(new SocketHeartBeatHelper.SendDataBuilder() {
        @Override
        public byte[] obtainSendHeartBeatData(SocketHeartBeatHelper helper) {
            /**
             * 使用当前日期作为心跳包
             */
            byte[] heartBeatPrefix = new byte[]{0x1F, 0x1F};
            byte[] heartBeatSuffix = new byte[]{0x1F, 0x1F};

            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
            byte[] heartBeatInfo = CharsetUtil.stringToData(sdf.format(new Date()), CharsetUtil.UTF_8);

            byte[] data = new byte[heartBeatPrefix.length + heartBeatSuffix.length + heartBeatInfo.length];
            System.arraycopy(heartBeatPrefix, 0, data, 0, heartBeatPrefix.length);
            System.arraycopy(heartBeatInfo, 0, data, heartBeatPrefix.length, heartBeatInfo.length);
            System.arraycopy(heartBeatSuffix, 0, data, heartBeatPrefix.length + heartBeatInfo.length, heartBeatSuffix.length);

            return data;
        }
    });

    /**
     * 设置远程端发送到本地的心跳包信息的检测器,用于判断接收到的数据包是否是心跳包
     * 通过{@link SocketResponsePacket#isHeartBeat()} 查看数据包是否是心跳包
     */
    socketClient.getHeartBeatHelper().setReceiveHeartBeatPacketChecker(new SocketHeartBeatHelper.ReceiveHeartBeatPacketChecker() {
        @Override
        public boolean isReceiveHeartBeatPacket(SocketHeartBeatHelper helper, SocketResponsePacket packet) {
            /**
             * 判断数据包信息是否含有指定的心跳包前缀和后缀
             */
            byte[] heartBeatPrefix = new byte[]{0x1F, 0x1F};
            byte[] heartBeatSuffix = new byte[]{0x1F, 0x1F};

            if (Arrays.equals(heartBeatPrefix, Arrays.copyOfRange(packet.getData(), 0, heartBeatPrefix.length))
                    && Arrays.equals(heartBeatSuffix, Arrays.copyOfRange(packet.getData(), packet.getData().length - heartBeatSuffix.length, packet.getData().length))) {
                return true;
            }

            return false;
        }
    });

    socketClient.getHeartBeatHelper().setHeartBeatInterval(10 * 1000); // 设置自动发送心跳包的间隔时长,单位毫秒
    socketClient.getHeartBeatHelper().setSendHeartBeatEnabled(true); // 设置允许自动发送心跳包,此值默认为false

自动按包尾分割信息读取数据的发送配置

    /**
     * 根据连接双方协议设置自动发送的包尾数据
     * 每次发送数据包(包括心跳包)都会在发送包内容后自动发送此包尾
     *
     * 例:socketClient.sendData(new byte[]{0x01, 0x02})的步骤为
     * 1. socketClient向远程端发送包头(如果设置了包头信息)
     * 2. socketClient向远程端发送正文数据{0x01, 0x02}
     * 3. socketClient向远程端发送包尾
     *
     * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadToTrailer}必须设置此项
     * 用于分隔多条消息
     */
    socketClient.getSocketPacketHelper().setSendTrailerData(new byte[]{0x13, 0x10});

    /**
     * 根据连接双方协议设置自动发送的包头数据
     * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包头
     *
     * 若无需包头可删除此行
     */
    socketClient.getSocketPacketHelper().setSendHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));

    /**
     * 设置分段发送数据长度
     * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
     *
     * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
     */
    socketClient.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
    socketClient.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false

    /**
     * 设置发送超时时长
     * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
     * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
     *
     * 若无需限制发送时长可删除此二行
     */
    socketClient.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
    socketClient.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false

自动按包尾分割信息读取数据的接收配置

    /**
     * 设置读取策略为自动读取到指定的包尾
     */
    socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.AutoReadToTrailer);

    /**
     * 根据连接双方协议设置的包尾数据
     * 每次接收数据包(包括心跳包)都会在检测接收到与包尾数据相同的byte[]时回调一个数据包
     *
     * 例:自动接收远程端所发送的socketClient.sendData(new byte[]{0x01, 0x02})【{0x01, 0x02}为将要接收的数据】的步骤为
     * 1. socketClient接收包头(如果设置了包头信息)(接收方式为一直读取到与包头相同的byte[],即可能过滤掉包头前的多余信息)
     * 2. socketClient接收正文和包尾(接收方式为一直读取到与尾相同的byte[])
     * 3. socketClient回调数据包
     *
     * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadToTrailer}必须设置此项
     * 用于分隔多条消息
     */
    socketClient.getSocketPacketHelper().setReceiveTrailerData(new byte[]{0x13, 0x10});

    /**
     * 根据连接双方协议设置的包头数据
     * 每次接收数据包(包括心跳包)都会先接收此包头
     *
     * 若无需包头可删除此行
     */
    socketClient.getSocketPacketHelper().setReceiveHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));

    /**
     * 设置接收超时时长
     * 在指定时长内没有数据到达本地自动断开
     *
     * 若无需限制接收时长可删除此二行
     */
    socketClient.getSocketPacketHelper().setReceiveTimeout(120 * 1000); // 设置接收超时时长,单位毫秒
    socketClient.getSocketPacketHelper().setReceiveTimeoutEnabled(true); // 设置允许使用接收超时时长,此值默认为false

自动按包长度信息读取的发送配置

    /**
     * 设置包长度转换器
     * 即每次发送数据时,将包头以外的数据长度转换为特定的byte[]发送到远程端用于解析还需要读取多少长度的数据
     *
     * 例:socketClient.sendData(new byte[]{0x01, 0x02})的步骤为
     * 1. socketClient向远程端发送包头(如果设置了包头信息)
     * 2. socketClient要发送的数据为{0x01, 0x02},长度为2(若设置了包尾,还需加上包尾的字节长度),通过此转换器将int类型的2转换为4字节的byte[],远程端也照此算法将4字节的byte[]转换为int值
     * 3. socketClient向远程端发送转换后的长度信息byte[]
     * 4. socketClient向远程端发送正文数据{0x01, 0x02}
     * 5. socketClient向远程端发送包尾(如果设置了包尾信息)
     *
     * 此转换器用于第二步
     *
     * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}必须设置此项
     * 用于分隔多条消息
     */
    socketClient.getSocketPacketHelper().setSendPacketLengthDataConvertor(new SocketPacketHelper.SendPacketLengthDataConvertor() {
        @Override
        public byte[] obtainSendPacketLengthDataForPacketLength(SocketPacketHelper helper, int packetLength) {
            /**
             * 简单将int转换为byte[]
             */
            byte[] data = new byte[4];
            data[3] = (byte) (packetLength & 0xFF);
            data[2] = (byte) ((packetLength >> 8) & 0xFF);
            data[1] = (byte) ((packetLength >> 16) & 0xFF);
            data[0] = (byte) ((packetLength >> 24) & 0xFF);
            return data;
        }
    });

    /**
     * 根据连接双方协议设置自动发送的包头数据
     * 每次发送数据包(包括心跳包)都会在发送包内容前自动发送此包头
     *
     * 若无需包头可删除此行
     */
    socketClient.getSocketPacketHelper().setSendHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));

    /**
     * 根据连接双方协议设置自动发送的包尾数据
     * 每次发送数据包(包括心跳包)都会在发送包内容后自动发送此包尾
     *
     * 若无需包尾可删除此行
     * 注意:
     * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}时不依赖包尾读取数据
     */
    socketClient.getSocketPacketHelper().setSendTrailerData(new byte[]{0x13, 0x10});

    /**
     * 设置分段发送数据长度
     * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
     *
     * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
     */
    socketClient.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
    socketClient.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false

    /**
     * 设置发送超时时长
     * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
     * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
     *
     * 若无需限制发送时长可删除此二行
     */
    socketClient.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
    socketClient.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false

自动按包长度信息读取的接收配置

    /**
     * 设置读取策略为自动读取指定长度
     */
    socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.AutoReadByLength);

    /**
     * 设置包长度转换器
     * 即每次接收数据时,将远程端发送到本地的长度信息byte[]转换为int,然后读取相应长度的值
     *
     * 例:自动接收远程端所发送的socketClient.sendData(new byte[]{0x01, 0x02})【{0x01, 0x02}为将要接收的数据】的步骤为
     * 1. socketClient接收包头(如果设置了包头信息)(接收方式为一直读取到与包头相同的byte[],即可能过滤掉包头前的多余信息)
     * 2. socketClient接收长度为{@link SocketPacketHelper#getReceivePacketLengthDataLength()}(此处设置为4)的byte[],通过下面设置的转换器,将byte[]转换为int值,此int值暂时称为X
     * 3. socketClient接收长度为X的byte[]
     * 4. socketClient接收包尾(如果设置了包尾信息)(接收方式为一直读取到与包尾相同的byte[],如无意外情况,此处不会读取到多余的信息)
     * 5. socketClient回调数据包
     *
     * 此转换器用于第二步
     *
     * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}必须设置此项
     * 用于分隔多条消息
     */
    socketClient.getSocketPacketHelper().setReceivePacketLengthDataLength(4);
    socketClient.getSocketPacketHelper().setReceivePacketDataLengthConvertor(new SocketPacketHelper.ReceivePacketDataLengthConvertor() {
        @Override
        public int obtainReceivePacketDataLength(SocketPacketHelper helper, byte[] packetLengthData) {
            /**
             * 简单将byte[]转换为int
             */
            int length =  (packetLengthData[3] & 0xFF) + ((packetLengthData[2] & 0xFF) << 8) + ((packetLengthData[1] & 0xFF) << 16) + ((packetLengthData[0] & 0xFF) << 24);

            return length;
        }
    });

    /**
     * 根据连接双方协议设置的包头数据
     * 每次接收数据包(包括心跳包)都会先接收此包头
     *
     * 若无需包头可删除此行
     */
    socketClient.getSocketPacketHelper().setReceiveHeaderData(CharsetUtil.stringToData("SocketClient:", CharsetUtil.UTF_8));

    /**
     * 根据连接双方协议设置的包尾数据
     *
     * 若无需包尾可删除此行
     * 注意:
     * 使用{@link com.vilyever.socketclient.helper.SocketPacketHelper.ReadStrategy.AutoReadByLength}时不依赖包尾读取数据
     */
    socketClient.getSocketPacketHelper().setReceiveTrailerData(new byte[]{0x13, 0x10});

    /**
     * 设置接收超时时长
     * 在指定时长内没有数据到达本地自动断开
     *
     * 若无需限制接收时长可删除此二行
     */
    socketClient.getSocketPacketHelper().setReceiveTimeout(120 * 1000); // 设置接收超时时长,单位毫秒
    socketClient.getSocketPacketHelper().setReceiveTimeoutEnabled(true); // 设置允许使用接收超时时长,此值默认为false

手动读取的发送配置

    /**
     * 设置分段发送数据长度
     * 即在发送指定长度后通过 {@link SocketClientSendingDelegate#onSendingPacketInProgress(SocketClient, SocketPacket, float, int)}回调当前发送进度
     *
     * 若无需进度回调可删除此二行,删除后仍有【发送开始】【发送结束】的回调
     */
    socketClient.getSocketPacketHelper().setSendSegmentLength(8); // 设置发送分段长度,单位byte
    socketClient.getSocketPacketHelper().setSendSegmentEnabled(true); // 设置允许使用分段发送,此值默认为false

    /**
     * 设置发送超时时长
     * 在发送每个数据包时,发送每段数据的最长时间,超过后自动断开socket连接
     * 通过设置分段发送{@link SocketPacketHelper#setSendSegmentEnabled(boolean)} 可避免发送大数据包时因超时断开,
     *
     * 若无需限制发送时长可删除此二行
     */
    socketClient.getSocketPacketHelper().setSendTimeout(30 * 1000); // 设置发送超时时长,单位毫秒
    socketClient.getSocketPacketHelper().setSendTimeoutEnabled(true); // 设置允许使用发送超时时长,此值默认为false

手动读取的接收配置

    /**
     * 设置读取策略为手动读取
     * 手动读取有两种方法
     * 1. {@link SocketClient#readDataToData(byte[], boolean)} )} 读取到与指定字节相同的字节序列后回调数据包
     * 2. {@link SocketClient#readDataToLength(int)} 读取指定长度的字节后回调数据包
     *
     * 此时SocketPacketHelper中其他读取相关设置将会无效化
     */
    socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.Manually);

常用回调配置

    // 对应removeSocketClientDelegate
    socketClient.registerSocketClientDelegate(new SocketClientDelegate() {
        /**
         * 连接上远程端时的回调
         */
        @Override
        public void onConnected(SocketClient client) {
             SocketPacket packet = socketClient.sendData(new byte[]{0x02}); // 发送消息
             packet = socketClient.sendString("sy hi!"); // 发送消息

             socketClient.cancelSend(packet); // 取消发送,若在等待发送队列中则从队列中移除,若正在发送则无法取消
        }

        /**
         * 与远程端断开连接时的回调
         */
        @Override
        public void onDisconnected(SocketClient client) {
            // 可在此实现自动重连
            socketClient.connect();
        }

        /**
         * 接收到数据包时的回调
         */
        @Override
        public void onResponse(final SocketClient client, @NonNull SocketResponsePacket responsePacket) {
            byte[] data = responsePacket.getData(); // 获取接收的byte数组,不为null
            String message = responsePacket.getMessage(); // 获取按默认设置的编码转化的String,可能为null
        }
    });

发送状态回调配置

    // 对应removeSocketClientSendingDelegate
    socketClient.registerSocketClientSendingDelegate(new SocketClientSendingDelegate() {
        /**
         * 数据包开始发送时的回调
         */
        @Override
        public void onSendPacketBegin(SocketClient client, SocketPacket packet) {
        }

        /**
         * 数据包取消发送时的回调
         * 取消发送回调有以下情况:
         * 1. 手动cancel仍在排队,还未发送过的packet
         * 2. 断开连接时,正在发送的packet和所有在排队的packet都会被取消
         */
        @Override
        public void onSendPacketCancel(SocketClient client, SocketPacket packet) {
        }

        /**
         * 数据包发送的进度回调
         * progress值为[0.0f, 1.0f]
         * 通常配合分段发送使用
         * 可用于显示文件等大数据的发送进度
         */
        @Override
        public void onSendingPacketInProgress(SocketClient client, SocketPacket packet, float progress, int sendedLength) {
        }

        /**
         * 数据包完成发送时的回调
         */
        @Override
        public void onSendPacketEnd(SocketClient client, SocketPacket packet) {
        }
    });

接收状态回调配置

    // 对应removeSocketClientReceiveDelegate
    socketClient.registerSocketClientReceiveDelegate(new SocketClientReceivingDelegate() {
        /**
         * 开始接受一个新的数据包时的回调
         */
        @Override
        public void onReceivePacketBegin(SocketClient client, SocketResponsePacket packet) {
        }

        /**
         * 完成接受一个新的数据包时的回调
         */
        @Override
        public void onReceivePacketEnd(SocketClient client, SocketResponsePacket packet) {
        }

        /**
         * 取消接受一个新的数据包时的回调
         * 在断开连接时会触发
         */
        @Override
        public void onReceivePacketCancel(SocketClient client, SocketResponsePacket packet) {
        }

        /**
         * 接受一个新的数据包的进度回调
         * progress值为[0.0f, 1.0f]
         * 仅作用于ReadStrategy为AutoReadByLength的自动读取
         * 因AutoReadByLength可以首先接受到剩下的数据包长度
         */
        @Override
        public void onReceivingPacketInProgress(SocketClient client, SocketResponsePacket packet, float progress, int receivedLength) {
        }
    });

License

Apache License Version 2.0

androidsocketclient's People

Contributors

ezekielzhang avatar vilyever avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

androidsocketclient's Issues

数据编码问题

我注意到,该库发送和接收都是 utf-8 编码,我们的数据需要 gbk 编码

问题是:发送和接收的时候,可否指定编码格式?:laughing: :laughing:

Failed to resolve: com.github.vilyever:AndroidSocketClient:1.2.1

qq 20160330145904

看了下这个库,不错。

我在添加 gradle 依赖时出现上面错误,我的配置如下:
project 下的 gradle 脚本里添加:

allprojects {
    repositories {
        maven { url "https://jitpack.io" }
        jcenter()
    }
}

app 的 gradle 脚本里添加依赖:

dependencies {
    compile 'com.github.vilyever:AndroidSocketClient:1.2.1'
}

哪里配置不对吗?

奇怪的现象

客户端没有向服务端发送数据,但是日志里面有下面的日志,这是为什么?求解释
onReceive:SocketClient: onReceivePacketBegin: 1113338328
03-03 14:31:06.369 9766-9766/com.hthy.qihuo E/lmb: onSend:SocketClient: onSendPacketBegin: 1113371672 [72, 101, 97, 114, 116, 66, 101, 97, 116]
03-03 14:31:06.379 9766-9766/com.hthy.qihuo E/lmb: onSend:SocketClient: onSendingPacketInProgress: 1113371672 : 0.0 : 0
03-03 14:31:06.379 9766-9766/com.hthy.qihuo E/lmb: onSend:SocketClient: onSendingPacketInProgress: 1113371672 : 0.4642857 : 13
03-03 14:31:06.379 9766-9766/com.hthy.qihuo E/lmb: onSend:SocketClient: onSendingPacketInProgress: 1113371672 : 0.60714287 : 17
03-03 14:31:06.379 9766-9766/com.hthy.qihuo E/lmb: onSend:SocketClient: onSendingPacketInProgress: 1113371672 : 0.89285713 : 25
03-03 14:31:06.379 9766-9766/com.hthy.qihuo E/lmb: onSend:SocketClient: onSendingPacketInProgress: 1113371672 : 0.9285714 : 26

关于Socket请求问题的咨询

可以用于Socket通讯吗?现在不知道服务端的怎么写的,但是只是知道是Socket通讯,不知道可不可以用这个框架

真机链接不上

我这边真机一连上就断开链接,然后我在断开链接里面重复去去链接,循环几次之后,会连上,然后,一发送数据,又直接断开链接,请问出现这种情况的原因有哪些呢?真机确实有网。

经常会报空指针

java.lang.NullPointerException
Attempt to invoke virtual method 'com.vilyever.socketclient.helper.SocketPacketHelper$ReadStrategy com.vilyever.socketclient.helper.SocketPacketHelper.getReadStrategy()' on a null object reference
com.vilyever.socketclient.SocketClient$ReceiveThread.run(SocketClient.java:1216)

只有第一次能接收到服务器发送的信息,但不完整.后面有新消息,onResponse不触发

我在onConnected的回调里设置了 socketClient.getSocketPacketHelper().setReadStrategy(SocketPacketHelper.ReadStrategy.Manually);
socketClient.readDataToLength(CharsetUtil.stringToData("Server accepted", CharsetUtil.UTF_8).length);
只有在服务器第一次发送消息是能收到,但是信息不完整. 而后面服务器再发新消息(IOS设备能收到),我这里就收不到了,onResponse没响应。
我有用心跳包保持长连接,客户端发送信息到服务器没有出现问题。现在就是接收服务器信息出现问题,服务器发送的信息没有包头和包尾只有正文。求助

自定义协议

公司服务器是 C 写的有自定义协议:格式是module_type类型和mess_length数据长度,请问是用哪个方。。还有就是getInputStream和getOutputStream这些我都不用写了吗?

Builder 设计模式

👍
另外,刚看了一个博客,说到:

当实例化一个类时有很多可选参数的时候,我们或许会写很多不同参数的构造方法,可读性会非常差,并且客户端也不知道在什么时候用什么构造器,这是非常非常糟糕的,同样静态方工厂也不能避免,这个时候我们需要用到构建器,也即设计模式里的Builder模式

我注意到你最新的1.3.3里面的 SocketPacket 类有很多构造方法,并且也遇到可读性差问题,是否可以考虑下 Builder 设计模式。
💯

3.0.0 设置固定发送心跳包。接收不到服务端发来的消息

RT

    socketClient.getHeartBeatHelper().setDefaultSendData(HBBytes);//字节数组心跳包
    socketClient.getHeartBeatHelper().setHeartBeatInterval(5 * 1000); // 设置自动发送心跳包的间隔时长,单位毫秒
    socketClient.getHeartBeatHelper().setSendHeartBeatEnabled(true); // 设置允许自动发送心跳包,此值默认为false

2.0.3时,发送字符数组心跳包,正常接收

希望可以支持ssl /tls

瞄了一眼,看来也是基于java.net.socket的,而java.net.socket有个扩展javax.net.ssl.SSLSocket是可以跑ssl、tls的,希望可以支持!

TimerTick报错

Socket客户端与服务端连接,长时间运行后,客户端会报错, 下面代码第一行报错:
if (getSocketConfigure().getSocketPacketHelper().isSendTimeoutEnabled()
&& getLastSendMessageTime() != NoSendingTime) {
if (currentTime - getLastSendMessageTime() >= getSocketConfigure().getSocketPacketHelper().getSendTimeout()) {
disconnect();
}
}
报错如下:
10-11 09:10:55.186 24080-5718/com.njsyg.myapplication E/AndroidRuntime: FATAL EXCEPTION: Thread-1887
java.lang.NullPointerException
at com.vilyever.socketclient.SocketClient.__i__onTimeTick(SocketClient.java:954)
at com.vilyever.socketclient.SocketClient.access$600(SocketClient.java:33)
at com.vilyever.socketclient.SocketClient$5$1.run(SocketClient.java:455)
at java.lang.Thread.run(Thread.java:856)

建议使用AlarmManager做心跳机制

最近我在做一个需要各种维持长连接的应用,同时要用到mqtt和socket。在研究eclipse.paho的mqtt client的时候,我发现在一些机型上,即使发送心跳,安卓系统也有可能让网络连接休眠,从而导致连接中断。paho默认是使用Timer来控制心跳发送的。我经过尝试和研究,发现使用AlarmManager来控制定时发送可以有效避免这种问题。paho的设计非常完善,心跳包发送的模块是可插拔的,可以自己插入一个实现了MqttPingSender接口的对象来控制发送心跳。于是很轻松的在不破坏源码的情况下用Alarm机制替换了原来的Timer机制。我在学习您的源代码过程中,看到您的心跳机制是使用了Handler.postDelayed的机制,经过实验,发现和Timer会导致一样的问题。希望您看到后有空能实验一下。^_^(我认为很可能Alarm机制不占用CPU资源,从而能达到更好的省电效果,从而避免了被系统列入高耗电后台应用从而导致被限制的情况)

咨询,response 会发给所有SocketClientDelegate,会不会导致消息乱掉

在SocketClient的__i__onReceiveResponse代码中,请求的responsepacket会发给所有SocketClientDelegate,问题是SocketClientDelegate里面就得判断是不是它的resp,还要维护SocketClientDelegate的生命周期

private void __i__onReceiveResponse(@NonNull final SocketResponsePacket responsePacket) {
   ......
    if (getSocketClientDelegates().size() > 0) {
        ArrayList<SocketClientDelegate> delegatesCopy =
                (ArrayList<SocketClientDelegate>) getSocketClientDelegates().clone();
        int count = delegatesCopy.size();
        for (int i = 0; i < count; ++i) {
            delegatesCopy.get(i).onResponse(this, responsePacket);
        }
    }
}

这个

怎么设置为『收到什么就立刻返回什么』的模式?

这个库功能有点复杂,现在卡在ReadStrategy了,我需要的很简单,就是收到什么就返回什么,收到多少就立刻返回多少,不需要包头包尾包长之类的。找了半天似乎没发现有这个模式,除了自己改以外,有没有简单的方法?谢谢!

读取汉字乱码的问题

在SocketInputReader.java下,readBytes方法117行,list.add((byte) c)这行会导致汉字乱码,
应该替换成

if (!Character.isIdeographic(c)) {
 list.add((byte) c);
} else {
byte[] bytes = new String(new char[] { (char) c }).getBytes("UTF-8");
for (byte b : bytes) {
list.add(b);
 }
}

有其它更好的方式吗?

onResponse 执行多次

socketClient.registerSocketDelegate(new SocketClient.SocketDelegate() {
@OverRide
public void onConnected(SocketClient client) {
LogUtil.e("SOCKET onConnected!!!!!!!" + client.getState());

            //socket 断开自动重新登录
            if(skDisconnect){
                NetRequest.login();
                skDisconnect = false;
            }
        }

        @Override
        public void onDisconnected(SocketClient client) {
            skDisconnect = true;
            LogUtil.e("SOCKET Disconnected!!!!!!!  count = "+count);
            if(count < 15){
                count++;
                serviceRun();
            }
        }

        @Override
        public void onResponse(SocketClient client, @NonNull SocketResponsePacket responsePacket) {
            // byte[] data = responsePacket.getData(); // 获取byte[]数据
            String msg = responsePacket.getMessage(); // 使用默认编码获取String消息
            LogUtil.e("onResponse   MSG = "+msg);
            if(!preMsg.equals(msg)){
                preMsg = msg;
                intent.putExtra("data", msg);
                sendBroadcast(intent);
            }

        }
    });

接收不到来自服务端传送过来的消息

我使用这个库,可以实现send操作,但是试过设置各种ReadStrategy,在通用回调里onResponse收不到任何信息.ios的同事可以收到socket服务端推过来的,但我就收不到.连onResponse打Log都没有触发,是否有什么必要条件要先配置,才能触发接收?

接收不到数据

你好 我不知道哪里没有弄好 接收不到数据 自己写的socket就可以 demo也看不出来哪里的问题 请问除了文档上 还有什么地方需要配置一下呢

心跳包不断变化问题

现在我的问题是心跳包包含消息流水号,心跳包每次都是变化的

我现在的处理是每隔一段时间发送数据,把该数据作为心跳包

请问还有没有别的方式?

请问如何修改心跳包格式呢?

看到文档中只提到:socketClient.setHeartBeatInterval(1000 * 30); // 设置心跳包发送间隔
那么如何自定义它的发送格式?因为有时候会根据服务端设置

一包的数据长度过大时会比较慢

定义的是按长度自动接收,然后有一包的长度大概在10W左右,接收到数据的时候会延迟1-2S,现在用你要处理的数据要比较的即使,不知道能不能有办法解决

socket连接不了!!!

简单的与服务器连接,下面几句够了吗?为啥我连接不上,在监听逻辑里 回调不了,希望大神说明下
if (localSocketClient == null) {
this.localSocketClient = new SocketClient();
socketClient.getAddress().setRemoteIP(AppConfig.REMOTE_IP); // 远程端IP地址
socketClient.getAddress().setRemotePort("8911"); // 远程端端口号
socketClient.getAddress().setConnectionTimeout(15 * 1000); // 连接超时时长,单位毫秒

}

心跳CountDownTimer疑似有bug:出现异常:Can't create handler inside thread that has not called Looper.prepare

java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare() at android.os.Handler.<init>(Handler.java:200) at android.os.Handler.<init>(Handler.java:114) at android.os.CountDownTimer$1.<init>(CountDownTimer.java:114) at android.os.CountDownTimer.<init>(CountDownTimer.java:114) at com.vilyever.socketclient.SocketClient$5.<init>(SocketClient.java:449) at com.vilyever.socketclient.SocketClient.getHearBeatCountDownTimer(SocketClient.java:449) at com.vilyever.socketclient.SocketClient$DisconnectionThread.run(SocketClient.java:1048)

注释心跳功能相关代码后,运行(暂时)正常

使用问题

刚使用了下,遇到个问题:
SocketClient 的构造方法

public SocketClient(@NonNull String remoteIP, int remotePort) {
        this(remoteIP, remotePort, DefaultConnectionTimeout);
    }

里面的第一个参数是客户端的 ip ?我现在是用一个调试工具,建了个 socket 服务端:

qq 20160331105631
需要和这个服务端通信,该如何处理呢?

我如下使用

mSocketClient = new SocketClient("192.168.1.108", 60000);
mSocketClient.connect();

结果是未连接,该如何操作呢?

增加别名有什么好处呢?

刚更新到1.5.1

发送字节数组可以有三个方法:

mSocketClient.sendBytes(mBytes);
mSocketClient.send(mBytes);
mSocketClient.sendData(mBytes);

看了下,都是调用 sendData 方法,这样有什么好处呢?

sendString 同样的东西。

个人感觉各一个就够了:

sendStringsendBytes

SocketClient 接收不到消息

服务端发送字符串:33\r\n

SocketClient 客户端利用 SocketDelegateonResponse 方法接收不到数据?

        getLocalSocketClient().registerSocketDelegate(new SocketClient.SocketDelegate() {
            @Override
            public void onConnected(SocketClient client) {
                Log.d("jpjpjp", "localSocketClient onConnected");
            }

            @Override
            public void onDisconnected(SocketClient client) {
                Log.w("jpjpjp", "localSocketClient onDisconnected");
            }

            @Override
            public void onResponse(SocketClient client, @NonNull String response) {
                Log.i("jpjpjp", "localSocketClient onResponse \n" + response);//获取不到数据
            }
        });

心跳包设置字节数组

心跳包只能是字符串吗?

现在遇到个问题:发送一个字符串 "7D82010000107702200435009B7A7D" ,我采用下面两种方式:

1 字符串转化为16进制字节数组,然后 >mSocketClient.send(mBytes)
2 设置该字符串为心跳包

这两个发送的数据不一样,设置编码格式为gbk和utf-8都不一样,求破?

Android端接收不到数据

1、当不设置读取方式的时候,只在接收超过15个字节的时候可以接收,而且接收后断连。当修改disconnect时,第二次数据接受不成功
2、当设置按长度接收数据的时候,数据不能接收。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.