[心缘地方]同学录
首页 | 功能说明 | 站长通知 | 最近更新 | 编码查看转换 | 代码下载 | 常见问题及讨论 | 《深入解析ASP核心技术》 | 王小鸭自动发工资条VBA版
登录系统:用户名: 密码: 如果要讨论问题,请先注册。

[备忘]瞎写的一个socket流转消息的类

上一篇:[备忘]HttpClient如何Gzip压缩。
下一篇:[靠]Jboss7启动后,端口访问不了

添加日期:2017/4/7 12:49:50 快速返回   返回列表 阅读1551次


package com.xxx.eterm;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;

public class ReadThread extends Thread {

    private BufferedInputStream in = null;

    ByteBuffer buffer = ByteBuffer.allocate(1024);

    public ReadThread(BufferedInputStream in) {
        this.in = in;
    }

    @Override
    public void run() {

        // 登录特殊:发送01 A2..,返回00 14..,前两个字节就是总长度
        // 以下是第3和4字节是总长度
        // 心跳:发送01 FB 00 05 00 ,返回01 FA 00 05 00
        // 未知命令:发送01 FE 00 11..,返回01 FD 00 06 ..
        // 未知命令:发送01 F9 00 44..,返回01 00 00 1A..
        // 看票号:发送01 00 00 2B..,返回01 00 02 73..

        byte[] data = new byte[64];
        int readLength = 0;
        try {
            while (in != null && (readLength = in.read(data)) != -1) {

                // 有效数据,写入buffer
                byte[] temp = new byte[readLength];
                System.arraycopy(data, 0, temp, 0, readLength);
                buffer.put(temp);

                // 解析数据Frame
                parseFrame();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("end read.");
    }

    private void parseFrame() {

        // 设置当前位置为数据结束位置,指针指向0
        buffer.flip();

        // 可能有多个消息
        while (buffer.limit() > 4) {

            // 如果是指定的消息头
            if (buffer.get(0) == (byte) 0x01 && buffer.get(1) == (byte) 0xFA
                    || buffer.get(0) == (byte) 0x01
                    && buffer.get(1) == (byte) 0xFD
                    || buffer.get(0) == (byte) 0x01
                    && buffer.get(1) == (byte) 0x00) {
                int dataLength = buffer.get(2) * 256 + buffer.get(3);
                if (buffer.limit() >= dataLength) {

                    // 把消息拆出来
                    byte[] msg = new byte[dataLength];
                    buffer.position(0);
                    buffer.get(msg, 0, dataLength); // 从buffer的当前位置读取数据,指针会移动

                    // 放到队列
                    MsgCenter.putMsg(msg);

                    // 压缩缓存
                    buffer.compact(); // limit重置为容量最大值,指针指向数据最后,可以继续写入数据
                    buffer.flip(); // 设置当前位置为数据结束位置,指针指向0

                    // 继续while循环,解析下一个消息
                } else {
                    // 消息体不完整,继续接收数据
                    // 跳出while循环
                    buffer.position(0);
                    buffer.compact();// limit重置为容量最大值,指针指向数据最后,可以继续写入数据
                    break;
                }
            } else {
                // 不是指定的消息头,丢弃
                // 找到第一个0x01,之前的都丢弃。如果没找到,全部丢弃。
                // 第一个0x01,可能是不想要的头,也得扔掉吧?那么就从下标1开始查找0x01
                int p = -1;
                for (int i = 1; i < buffer.limit(); i++) {
                    if (buffer.get(i) == (byte) 0x01) {
                        p = i;
                        break;
                    }
                }
                if (p == -1) {
                    buffer.clear();
                    break; // 跳出循环,继续接收数据
                } else {
                    buffer.position(p);
                    buffer.compact();
                    buffer.flip(); // 设置当前位置为数据结束位置,指针指向0
                    // 继续while循环,解析下一个消息
                }
            }
        }
        if (buffer.limit() <= 4) {
            buffer.position(0);
            buffer.compact();// limit重置为容量最大值,指针指向数据最后,可以继续写入数据
        }

    }

    /**
     * 输出buffer内容.
     */
    public void printBuffer(ByteBuffer buffer) {

        // 记住当前位置
        int p = buffer.position();

        // 指针挪到0
        buffer.position(0);

        // 循环输出每个字节内容
        for (int i = 0; i < buffer.limit(); i++) {
            byte b = buffer.get(); // 读操作,指针会自动移动
            v(Integer.toHexString(b));
        }

        byte[] msg = new byte[buffer.limit()];
        buffer.position(0);
        buffer.get(msg, 0, buffer.limit()); // 从buffer的当前位置读取数据,指针会移动
        try {
            System.out.println(new String(msg, "GBK"));
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        // 指针再挪回去
        buffer.position(p);

        // 本想用mark()和reset()来实现。
        // 但是,它们貌似只能正向使用。
        // 如,位置6的时候,做一下Mark,
        // 然后在位置10(位置要大于6)的时候,用reset就会跳回位置6.

        // 而position(n)这个方法,如果之前做了Mark,但是Mark位置大于新位置,Mark会被清除。
        // 也就是说,做了Mark后,只能向前跳,不能往回跳,否则Mark就丢失。
        // rewind()方法,更干脆,直接清除mark。
        // flip()方法,也清除mark
        // clear()方法,也清除mark
        // compact方法,也清除mark

        // 所以,mark方法干脆不要用了,自己拿变量记一下就完了。
    }

    public void v(Object o) {
        System.out.println(o);
    }
}

 

评论 COMMENTS
没有评论 No Comments.

添加评论 Add new comment.
昵称 Name:
评论内容 Comment:
验证码(不区分大小写)
Validation Code:
(not case sensitive)
看不清?点这里换一张!(Change it here!)
 
评论由管理员查看后才能显示。the comment will be showed after it is checked by admin.
CopyRight © 心缘地方 2005-2999. All Rights Reserved