搭建webSocket服务器核心

暑假在家研究了一下webSocket服务器

首先从webSocket原理讲解。b/s构架是基于http协议,这不是一个长连接,而且也分主动和被动。浏览器主动向服务器发出请求,等待服务器的响应到达,然后断开连接。这种方式的通信非常不适合不如聊天这种功能的实现。为了弥补这个缺陷,浏览器就有了webSocket(web套接字)这种新技术来再现socket(套接字)。但是与socket不同的是,它有发送格式的要求。

建议参考如下文章:WebSocket协议:5分钟从入门到精通

看完上一连接的文章后我对webSocket有了基本的了解,但是还是不太了解握手

接着就看了下面的文章:基于websocket的前端与后端之间的数据交互

知道了握手key的算法

但是还是不了解如何计算长度和获得内容的

于是就有下面这篇文章:WebSocket握手协议

里面有关键的代码,虽然是C/C++写的,但是还是思路是相同的

有了以上的知识储备,我就试着搭建了第一个webSocket服务器,准确的说是含有webSocket成分的服务器。我的目的是建设一个聊天服务器,已经能够在客户端实现,我还想在浏览器上实现,实现两方的三种情况都能通信,这就需要用到webSocket技术,我想在原有服务器的基础上新增几个类,用来将webSocket发来的数据帧转换成能用的格式,事实上确实成功了。

下面附上webSocket的关键代码


JAVA

用来生成握手钥匙(接着就看了下面的文章:基于websocket的前端与后端之间的数据交互

public static  String getWSSecretKey(String strWebSocketKey) {
        String MAGIC_KEY = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        MessageDigest shaMD = null;
        try {
            strWebSocketKey = strWebSocketKey + MAGIC_KEY;
            shaMD = MessageDigest.getInstance("SHA-1");
            shaMD.reset();
            shaMD.update(strWebSocketKey.getBytes());
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        byte messageDigest[] = shaMD.digest();
        BASE64Encoder b64 = new BASE64Encoder();
        return b64.encode(messageDigest);
    }


用来和浏览器握手

public static void responseConnection(Socket s) throws IOException{
        BufferedReader br=new BufferedReader(new InputStreamReader(s.getInputStream()));
        String result=br.readLine();
        String key="";
        String skey="";
        //!result.contains("\r\n")
        while(result.length()>0){
            if(result.contains("Sec-WebSocket-Key:")){
                key=result.split(": ")[1];
                skey=getWSSecretKey(key);
            }
            System.out.println(result);
            result=br.readLine();
        }    
        PrintStream ps=new PrintStream(s.getOutputStream());
        ps.println("HTTP/1.1 101 Switching Protocols");
        ps.println("Connection: Upgrade");
        ps.println("Upgrade: WebSocket");
        ps.println(("Sec-WebSocket-Accept: "+skey));
        ps.println("Sec-WebSocket-Location: ws://127.0.0.1:8008/");
        ps.println();
    }
    public static void responseConnection(Socket s,BufferedReader br ) throws IOException{
        String result=br.readLine();
        String key="";
        String skey="";
        //!result.contains("\r\n")
        while(result.length()>0){
            if(result.contains("Sec-WebSocket-Key:")){
                key=result.split(": ")[1];
                skey=getWSSecretKey(key);
            }
            System.out.println(result);
            result=br.readLine();
        }    
        PrintStream ps=new PrintStream(s.getOutputStream());
        ps.println("HTTP/1.1 101 Switching Protocols");
        ps.println("Connection: Upgrade");
        ps.println("Upgrade: WebSocket");
        ps.println(("Sec-WebSocket-Accept: "+skey));
        ps.println("Sec-WebSocket-Location: ws://127.0.0.1:8008/");
        ps.println();
    }


用来接收浏览器的数据帧,并且筛选出内容

public static byte[] getWebSocket(Socket s) throws IOException{
        InputStream is=s.getInputStream();
        byte[] result=null;
        int len=0;
        while((len=is.read())!=129);
        System.out.println("len: "+len);
        if(len==129){
            if((len=is.read()-128)<=125){
                int[] XOR=new int[4];
                XOR[0]=is.read();
                XOR[1]=is.read();
                XOR[2]=is.read();
                XOR[3]=is.read();
                System.out.println("len: "+len);
                result=new byte[len];
                for(int i=0;i<len;i++){
                    int t=is.read();
                    result[i]=(byte) (t^XOR[i%4]);
                    System.out.println(t);
                }
            }else if((len=is.read()-128)==126){
                
            }else if((len=is.read()-128)==127){
                
            }
        }else{
            System.out.println("len!=129");
            return "null".getBytes();
        }
        System.out.println("getWebSocket: "+new String(result,"UTF-8"));
        return result;
    }


用来将待发送文本包装成数据帧的格式发送到浏览器

public static void sendWebSocket(Socket s,String result) throws IOException{
        byte[] e=null;
        if(result.getBytes().length<=125){
            //byte[1]低7位表示数据长度,<=125时,后面不跟任何表示长度的字节
            e=new byte[]{(byte) 129,(byte) result.getBytes().length};
        }else if(result.getBytes().length<=65535){
            //byte[1]低7位表示数据长度,125<length<=65535时,后面跟两位表示长度的字节
            e=new byte[]{(byte) 129,(byte) 126,(byte) (result.getBytes().length>>8),(byte) result.getBytes().length};
        }else{
            //byte[1]低7位表示数据长度,65535<length<=8字节时,后面跟4位表示长度的字节
            e=new byte[]{(byte) 129,(byte) 127,(byte) (result.getBytes().length>>24),(byte) (result.getBytes().length>>16),(byte) (result.getBytes().length>>8),(byte) result.getBytes().length};
        }
        s.getOutputStream().write(e);
        s.getOutputStream().flush();
        s.getOutputStream().write(result.getBytes("UTF-8"));
        s.getOutputStream().flush();
    }

 

以上代码并没有考虑到所有情况,没有使用到webSocket的所有功能,仅仅满足了当前的需要,以后有时间一定要补充完整。                                       

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值