zoukankan      html  css  js  c++  java
  • WebSocket简介

    我只是程序员的搬运工=.=....借助一个比较随意的图来解释一下:

    流程:


    1. Client try to connect to WebSocket server
    2. Server recognize client
    3. If client is not registered with server then add client (this is known as handshaking process which is based on headers transmission)
    4. Send and receive data
    5. Close connection

    如果只需要了解WebSocket,上面的图应该就足够了,它包含一下内容:

    1. WebSocket的协议须通过HTTP请求建立(请求方式必须为GET,具体的握手协议属于高级内容).
    2. WebSocket的消息体被前缀(0x00)和后缀(0xff)包裹起来.
    3. 当消息体为空的时候=告诉服务器可以断开连接了.(这一条是我瞎猜的,没试过.先占个位置,有空尝试了修正.)

    接下来稍微深入一点点,以下内容纯属瞎掰,才学编程半年多,写错了敬请指正!

    握手协议:

      客户端请求建立握手协议:

    GET / HTTP/1.1                                      //请求格式为GET,url为"/",http协议版本必须在1.1及以上
    Upgrade: websocket                                  //Upgrade头域内容:websocket;告诉服务器需要升级到什么协议
    Connection: Upgrade                                 //Connection头域内容:Upgrade;控制可选操作为Upgrade
    Host: example.com                       //服务器主机地址
    Origin: null                         //来源地址
    Sec-WebSocket-Key: sN9cRrP/n9NdMgdcy2VJFQ==      //连接加密字符串
    Sec-WebSocket-Version: 13                 //WebSocket协议版本

      服务器返回结果:
    HTTP/1.1 101 Switching Protocols              //状态码101,服务器理解了客户端升级协议的请求
    Upgrade: websocket                     //协议将升级到WebSocket
    Connection: Upgrade                    //控制可选操作为Upgrade
    Sec-WebSocket-Accept: fFBooB7FAkLlXgRSz0BT3v4hq5s=  //根据客户端发送的key生成的加密值
    Sec-WebSocket-Origin: null                //来源地址
    Sec-WebSocket-Location: ws://example.com/        //WebSocket通信的地址

    接下来是消息格式:感谢http://www.cnblogs.com/smark/archive/2012/11/26/2789812.html....

    数据交互协议:

    这图有点难看懂...里面包括几种情况有掩码,数据长度小于126,小于UINT16和小于UINT64等几种情况.后面会慢慢详细说明.

    整个协议头大概分三部分组成:

    1. 描述消息结束情况和类型.
    2. 描述是否存在掩码长度.
    3. 扩展长度描述和掩码值.

    从图中可以看到WebSocket协议数据主要通过头两个字节来描述数据包的情况

    第一个字节

    最高位用于描述消息是否结束,如果为1则该消息为消息尾部,如果为零则还有后续数据包;后面3位是用于扩展定义的,如果没有扩展约定的情况则必须为0.可以通过以下c#代码方式得到相应值

    1 mDataPackage.IsEof = (data[start] >> 7) > 0;

    最低4位用于描述消息类型,消息类型暂定有15种,其中有几种是预留设置.c#代码可以这样得到消息类型:

    1 int type = data[start] & 0xF;
    2 mDataPackage.Type = (PackageType)type;

    第二个字节

    消息的第二个字节主要用一描述掩码和消息长度,最高位用0或1来描述是否有掩码处理,可以通过以下c#代码方式得到相应值

    1 bool hasMask = (data[start] >>7) > 0;

    剩下的后面7位用来描述消息长度,由于7位最多只能描述127所以这个值会代表三种情况,一种是消息内容少于126存储消息长度,如果消息长度少于UINT16的情况此值为126,当消息长度大于UINT16的情况下此值为127;这两种情况的消息长度存储到紧随后面的byte[],分别是UINT16(2位byte)和UINT64(4位byte).可以通过以下c#代码方式得到相应值

     1 mPackageLength = (uint)(data[start] & 0x7F);
     2 start++;
     3 if (mPackageLength == 126)
     4 {
     5     mPackageLength = BitConverter.ToUInt16(data, start);
     6     start = start + 2;
     7 }
     8 else if (mPackageLength == 127)
     9 {
    10     mPackageLength = BitConverter.ToUInt64(data, start);
    11     start = start + 8;
    12 }

    如果存在掩码的情况下获取4位掩码值:

    1 if (hasMask)
    2 {
    3     mDataPackage.Masking_key = new byte[4];
    4     Buffer.BlockCopy(data, start, mDataPackage.Masking_key, 0, 4);
    5            
    6     start = start + 4;
    7     count = count - 4;
    8 }

    获取消息体

    当得到消息体长度后就可以获取对应长度的byte[],有些消息类型是没有长度的如%x8 denotes a connection close.对于Text类型的消息对应的byte[]是相应字符的UTF8编码.获取消息体还有一个需要注意的地方就是掩码,如果存在掩码的情况下接收的byte[]要做如下转换处理:

    1 if (mDataPackage.Masking_key != null)
    2 {
    3     int length = mDataPackage.Data.Count;
    4     for (var i = 0; i < length; i++)
    5         mDataPackage.Data.Array[i] = (byte)mDataPackage.Data.Array[i]^mDataPackage.Masking_key[i % 4]);
    6 }

    以上,以后再补充,我消化不过来了....

     
     
  • 相关阅读:
    English Voice of <<Cups>>
    【线段树】奶牛排队(USACO 2007 January Gold)
    【线段树】买水果
    【线段树】卫星覆盖(NOI97)-矩阵切割
    插入排序 (Insertion Sort)
    选择排序 (Selection Sort)
    springboot整合redis
    redis入门及相关API
    mycat配置文件的详细介绍
    redis常用命令
  • 原文地址:https://www.cnblogs.com/snys98/p/4437162.html
Copyright © 2011-2022 走看看