js的二进制编码类

<script src="js/jquery.min.js"></script>
<script type="text/javascript" src="js/pako.min.js"></script>
<script>
$(document).ready(function(){
    //字符串转字节序列
    function stringToByte(str) {  
        var bytes = new Array();  
        var len, c;  
        len = str.length;  
        for(var i = 0; i < len; i++) {  
            c = str.charCodeAt(i);  
            if(c >= 0x010000 && c <= 0x10FFFF) {  
                bytes.push(((c >> 18) & 0x07) | 0xF0);  
                bytes.push(((c >> 12) & 0x3F) | 0x80);  
                bytes.push(((c >> 6) & 0x3F) | 0x80);  
                bytes.push((c & 0x3F) | 0x80);
            } else if(c >= 0x000800 && c <= 0x00FFFF) {  
                bytes.push(((c >> 12) & 0x0F) | 0xE0);  
                bytes.push(((c >> 6) & 0x3F) | 0x80);  
                bytes.push((c & 0x3F) | 0x80);
            } else if(c >= 0x000080 && c <= 0x0007FF) {  
                bytes.push(((c >> 6) & 0x1F) | 0xC0);  
                bytes.push((c & 0x3F) | 0x80);
            } else {  
                bytes.push(c & 0xFF);
            }  
        }  
        return bytes;  
    }
    function getStrLen(str) {  
        var len, c;  
        len = str.length;
        var byteLength=0;
        for(var i = 0; i < len; i++) {  
            c = str.charCodeAt(i);  
            if(c >= 0x010000 && c <= 0x10FFFF) {  
                byteLength+=4;
            } else if(c >= 0x000800 && c <= 0x00FFFF) {  
                byteLength+=3;
            } else if(c >= 0x000080 && c <= 0x0007FF) {  
                byteLength+=2;
            } else {  
                byteLength+=1;
            }  
        }  
        return byteLength;  
    }
    function byteToString(arr) {
        if(typeof arr === 'string') {
            return arr;
        }
        var str = '',_arr = arr;
        for(var i = 0; i < _arr.length; i++) {
            var one = _arr[i].toString(2),
                v = one.match(/^1+?(?=0)/);
            if(v && one.length == 8) {
                var bytesLength = v[0].length;
                var store = _arr[i].toString(2).slice(7 - bytesLength);
                for(var st = 1; st < bytesLength; st++) {
                    store += _arr[st + i].toString(2).slice(2);
                }
                str += String.fromCharCode(parseInt(store, 2));
                i += bytesLength - 1;
            } else {
                str += String.fromCharCode(_arr[i]);
            }
        }
        return str;
    }
    function Buffer(){
        var self=this;
        self.writerIndex_=0;
        self.readerIndex_=0;
        self.kInitialSize = 0;
        self.buffer_=new Array(self.kInitialSize);
    }
    Buffer.prototype = {
        readableBytes:function(){
            var self=this;
            return self.writerIndex_ - self.readerIndex_;
        },
        writableBytes:function()
        {
            var self=this;
            return self.buffer_.length - self.writerIndex_;
        },
        readData:function(buf){
            var self=this;
            var n=buf.byteLength;
            var dataView=new DataView(buf);
            for(var i=0;i<n;i++)
            {
                self.buffer_[self.writerIndex_+i]=dataView.getInt8(i);
            }
            self.writerIndex_+=n;
            return n;
        },
        //获取这么多字节的数据
        peek:function(len)
        {
            var self=this;
            var data=new ArrayBuffer(len);
            var dataView = new DataView(data);
            for(var i=self.readerIndex_;i<len;i++)
            {
                dataView.setInt8(i,self.buffer_[i]);
            }
            return data;
        },
        //把读指针往前挪len个字节
        retrieve:function(len){
            var self=this;
            //self.readerIndex_+=len;
            var temp=new Array();
            for(var i=len;i<self.writerIndex_;i++)
            {
                temp.push(self.buffer_[i]);
            }
            for(var i=0;i<self.buffer_.length;i++)
            {
                if(i<temp.length)
                {
                    self.buffer_[i]=temp[i];
                }else{
                    self.buffer_[i]=0;
                }
            }
            self.readerIndex_=0;
            self.writerIndex_=temp.length;
        }
    }
    function BinaryWriteStream(){
        var self=this;
        self._str=null;
        self._list = new Array();
        self._list2 = new Array();
        self._bytes=null;
    }
    BinaryWriteStream.prototype = {
        orgpress_:function(i,buf){
            var len = 0;
            for (var a = 4; a >= 0; a--)
            {
                var c;
                c = (i >> (a * 7) & 0x7f);
                if (c == 0x00 && len == 0)
                    continue;

                if (a == 0)
                    c &= 0x7f;
                else
                    c |= 0x80;
                buf[len]=c;
                len++;
            }
            if (len == 0)
            {
                len++;
                buf[0]=0;
            }
            return len;
        },
        intToBigEndian:function(n){
            var b = new Array(4);
            b[3] = (n & 0xff);
            b[2] = (n >> 8 & 0xff);
            b[1] = (n >> 16 & 0xff);
            b[0] = (n >> 24 & 0xff);
            return b;
        },
        writeInt32:function(i){
            var self = this;
            var tmp = self.intToBigEndian(i);
            for (var n = 0; n < tmp.length; ++n)
            {
                self._list.push(tmp[n]);
            }
            return true;
        },
        writeString:function(data){
            var len=getStrLen(data);
            var self = this;
            var buf = new Array(5);
            var orgpressLen = self.orgpress_(len, buf);

            for (var i = 0; i < orgpressLen; ++i)
            {
                self._list.push(buf[i]);
            }

            var strData = stringToByte(data);

            for (var j = 0; j < strData.length; ++j)
            {
                self._list.push(strData[j]);
            }
            return true;
        },
        flush:function(){
            var self = this;
            var length = self._list.length;
            var pkgHeader = new Array(6);
            pkgHeader[3] = (length & 0xff);
            pkgHeader[2] = (length >> 8 & 0xff);
            pkgHeader[1] = (length >> 16 & 0xff);
            pkgHeader[0] = (length >> 24 & 0xff);
            for (var i = 0; i < pkgHeader.length; ++i)
            {
                self._list2.push(pkgHeader[i]);
            }

            for (var k = 0; k < self._list.length; ++k)
            {
                self._list2.push(self._list[k]);
            }
            var bytesLength = self._list2.length;
            self._bytes = new Int8Array(bytesLength);

            for (var k = 0; k < bytesLength; ++k)
            {
                var xb = self._list2[k];
                if (xb == undefined)
                    self._bytes[k] = 0;
                else
                    self._bytes[k] = xb;
            }
        },
        getBytesArray:function(){
            var self = this;
            return self._bytes;
        },
        getSize:function(){
            var self = this;
            if (self._bytes != undefined)
                return self._bytes.length;
            else
                return 0;
        }
    }
    function BinaryReadStream(data){
        var self=this;
        self._data=data;
        self._cur=6;
    }
    BinaryReadStream.prototype = {
        ReadInt32:function(){
            var self=this;
            //返回最大值表示出错
            if (self._cur + 4 > self._data.length)
                return 0;

            var b = new Array(4);
            b[3] = self._data[self._cur + 3];
            b[2] = self._data[self._cur + 2];
            b[1] = self._data[self._cur + 1];
            b[0] = self._data[self._cur];

            var i =  b[3] & 0xFF |
                    (b[2] & 0xFF) << 8 |
                    (b[1] & 0xFF) << 16 |
                    (b[0] & 0xFF) << 24;

            self._cur += 4;
            return i;
        },
        ReadString:function(){
            var self=this;
            var headlen = self.readLengthWithoutOffset();
            // user buffer is not enough
            if (self._cur + headlen > self._data.length)
                return "";

            var bytes = new Array(headlen);
            for (var i = 0; i < headlen; ++i)
            {
                bytes[i] = self._data[self._cur + i];
            }

            self._cur += headlen;

            //String res = new String(bytes);
            //return res;
            return byteToString(bytes);
        },
        readLengthWithoutOffset:function() {
            var self=this;
            //buf数组中有效的位数
            var nValidHeadLength = 0;
            var buf = new Array(5);

            for (var i = 0; i< 5 ; i++)
            {
                buf[i] = self._data[self._cur+i];
                nValidHeadLength ++;

                if ((buf[i] & 0x80) == 0x00)
                    break;
            }

            self._cur += nValidHeadLength;

            return self.unorgpress_(buf, nValidHeadLength);
        },
        unorgpress_:function(buf,nValidLength) {
            var self=this;
            var i = 0;
            for (var index = 0; index < nValidLength; index++)
            {
                var c = buf[index];
                i = i << 7;

                c &= 0x7f;
                i |= c;
            }
            return i;
        }
    }
    var ws=new WebSocket('ws://localhost:9000');
    ws.binaryType = "arraybuffer";
    var pBuffer=new Buffer();
    ws.onopen=function(){
        $("#content").html("<li>客户端已连接</li>");
        //发送登录信息
        var json="{\"username\": \"张三\", \"password\": \"123456\", \"clienttype\": 1, \"status\": 3}";
        var bws=new BinaryWriteStream();
        bws.writeInt32(1002);
        bws.writeInt32(0);
        bws.writeString(json);
        bws.flush();
        var size=bws.getSize();
        console.log("bs size is:"+size);
        var buffer = new ArrayBuffer(25+size);
        var dv = new DataView(buffer,0);
        var arr=bws.getBytesArray();
        var arr2 = pako.deflate(arr);
        dv.setUint8(0,0);//消息类型
        dv.setUint32(1,size,true);//序列号,消息内容
        dv.setUint32(5,arr2.length,true);
        dv.setUint32(9,0);//填充空位
        dv.setUint32(13,0);
        dv.setUint32(17,0);
        dv.setUint32(21,0);
        var tmp = new Int8Array(buffer);
        tmp.set(new Int8Array(arr),25);//和下面等价
        /*for(var i=0;i<arr2.length;i++)
        {
            dv.setInt8(25+i,arr2[i]);
        }*/
        ws.send(buffer);
    }
    var MAX_PACKAGE_SIZE=10 * 1024 * 1024;
    function OnRead()
    {
        if (pBuffer.readableBytes() < 25)
        {
            //LOG_INFO << "buffer is not enough for a package header, pBuffer->readableBytes()=" << pBuffer->readableBytes() << ", sizeof(msg)=" << sizeof(msg);
            return;
        }
        var header=pBuffer.peek(25);
        var v=new DataView(header);
        var originsize=v.getUint32(1,true);
        var compresssize=v.getUint32(5,true);
        //取包头信息
        //数据包压缩过
        if (compresssize <= 0 || compresssize > MAX_PACKAGE_SIZE ||
            originsize <= 0 || originsize > MAX_PACKAGE_SIZE)
        {
            console.log("illegal package size");
            return;
        }

        //收到的数据不够一个完整的包
        if (pBuffer.readableBytes() < compresssize + 25)
            return;

        pBuffer.retrieve(25);
        var cdata=pBuffer.peek(compresssize);//取出压缩大小的数据
        pBuffer.retrieve(compresssize);
        //解压缩
        var orginData=pako.inflate(cdata);
        if (!Process(orginData))
        {
            //客户端发非法数据包,服务器主动关闭之
            LOG_ERROR << "Process error, close TcpConnection, client: " << conn->peerAddress().toIpPort();
            //conn->forceClose();
            console.log("包处理异常");
            return;
        }
    }
    function Process(data)
    {
        //调用二进制读取类
        var brs=new BinaryReadStream(data);
        var msg_type=brs.ReadInt32();
        var seq_id=brs.ReadInt32();
        var json=brs.ReadString();
        console.log(json);
        return true;
    }
    ws.onmessage=function(evt){
        $("#content").html("<li>"+evt.data+"</li>");
        var n = pBuffer.readData(evt.data);
        if (n > 0)
        {
            OnRead();
        }
    }
    ws.onclose=function(){
        $("#content").html("<li>客户端已断开连接</li>");
    };
    ws.οnerrοr=function(evt){
        $("#content").html("<li>"+evt.data+"</li>");
    };
    $("#send").click(function(){
        ws.send($("#message").val());
    });
    $("#connect").click(function(){
        ws=new WebSocket('ws://localhost:9000');
    });
});
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值