20190503(cmake安装,利用libwebsockets库去实现http服务器,websocket服务器,虚拟机安装) - Go语言中文社区

20190503(cmake安装,利用libwebsockets库去实现http服务器,websocket服务器,虚拟机安装)


目录

1.libwebsockets简介安装

2.libwebsockets实现简易http服务器

3.实现简易websocket服务器

4.websocket介绍

5.虚拟机安装


1.libwebsockets简介安装

https://blog.csdn.net/u013780605/article/details/79489183

(完全抄录原作者,抄录的目的是一为了一字不差看一遍,二是万一原作者删除了,我这还有一份)

ibwebsockets是一款轻量级用来开发服务器和客户端的C库。按照官方(https://libwebsockets.org/)给出的介绍来看,它不仅支持ws,wss还同时支持http与https,可以轻轻松松结合openssl等库来实现ssl加密。OK,本篇博客将介绍如何下载使用功能这么强大的库。

下载

git clone https://github.com/warmcat/libwebsockets.git

编译

为了可以进行多平台编译,websockets项目采用CMake作为编译工具,所以如果机器上没有CMake需要去安装CMake,以ubuntu为例。

  • 到官网https://cmake.org/download/下载最新版本的CMake源码;
  • 解压后进入源码根目录执行bootstrap
  • 然后进行编译make和安装sudo make install即可。

CMake安装完成之后我们需要进入libwebsockets源码目录下的build目录,然后执行cmake ..即开始源码的编译。执行完毕后将在build目录下生成文件,最后再build目录下执行make和make install命令即可完成编译安装。详细的编译选项和命令可以参见编译指导READMEs/README.build.md。

测试

在编译完成后,build/bin目录下将会生成一些学习用的样例,我们以libwebsockets-test-server为例来看看libwebsockets运行起来是什么样的。

首先执行./libwebsockets-test-server --help查看如何使用该可执行文件:

可选指定端口,支持ssl,日志文件与服务器资源目录
Usage: test-server [--port=<p>] [--ssl] [-d <log bitfield>] [--resource_path <path>] 

这里测试用的服务器资源目录已经安装在/usr/local/share/libwebsockets-test-server/目录下,默认即可。

./libwebsockets-test-server

执行完之后我们看到服务器已经开始运行在7681端口。

QQ截图20180307180332.png

 访问该网址和端口即可查看最终的效果(不要使用ie浏览器)。

 

本人安装:

1.CetOS下安装git

1.切换到root用户:su root

2.yum -y install git

3. rpm -qa|grep git 查看是否安装成功

4.创建git仓库

mkdir  harvey_git        // 创建文件夹
useradd harvey             //创建用户名并设置密码
passwd harvey            //(系统会提示输入密码和再次密码)
groupadd git        // 创建组

cd harvey_git
git init --bare        //进入所创建的文件夹,初始化一个仓库
chown -R six:git /home/harvey/Desktop/harvey_git/        // 赋权限

 

2. 下载libwebsockets

git clone https://github.com/warmcat/libwebsockets.git

 

3. cd libwwebsockets

4.mkdir build

5.cmake .. 

所以要先下载CMake源码 :https://cmake.org/download/

6.跳过第五步,到第六步,下载源码(6-31步骤都是在安装cmake)

7.拷贝到CentOS下解压:

 tar -xzvf cmake-3.14.3.tar.gz

8. cd  cmake-3.14.3

9. ./bootstrap

报错了,但未解决,看第十步

10.重新下了一版cmake,重复第7~9步骤,结果:文件都不全

11.安装wget:

yum -y install wget

11.在CentOS下下载cmake

 wget https://cmake.org/files/v3.12/cmake-3.12.2.tar.gz

12. cd cmake-3.12.2

13.  ./bootstrap

认真看了眼报错,发现与g++有关,用 g++ -v查看版本号,没有找到g++

14.yum -y install gcc-c++  

当前CentOS版本为6.8,update g++后为4.47 还是不支持C++11;

15.升级g++版本支持 -std=c++11 特性(16~23步骤是关于升级gcc的)

https://blog.csdn.net/centnethy/article/details/81284657

16.获取安装包并解压

wget http://ftp.gnu.org/gnu/gcc/gcc-6.1.0/gcc-6.1.0.tar.bz2

tar -jxvf gcc-6.1.0.tar.bz2

当然,http://ftp.gnu.org/gnu/gcc  里面有所有的gcc版本供下载,最新版本已经有6.1.0啦.

建议下载.bz2的压缩包,文件更小,下载时间更少.

17.下载供编译需求的依赖项

cd gcc-6.1.0

./contrib/download_prerequisites

18. 建立一个目录供编译出的文件存放 

mkdir gcc-build-6.1.0

cd gcc-build-6.1.0

19. 生成Makefile文件 

../configure -enable-checking=release -enable-languages=c,c++ -disable-multilib

20.编译 

make -j4

-j4选项是make对多核处理器的优化,如果不成功请使用 make,相关优化选项可以移步至参考文献[2]。

(注意:此步骤非常耗时,我虚拟机耗时近3小时; 实体机近80分钟,CPU基本是满的,内存也使用不少)

21.安装 

make install

(安装需要root权限!)

查看安装

ls /usr/local/bin | grep gcc

22.重启,然后查看gcc版本 

gcc -v

 

23. 写个C++11 特性的程序段 测试

g++ -std=c++11 test.cpp

24. ./bootstrap

Error when bootstrapping CMake:
Problem while running initial CMake

引导启动时出错:运行初始CHIGK时的问题

解决参考文章:https://blog.csdn.net/tigerleap/article/details/49100531

25.通过strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX查看

strings /usr/lib64/libstdc++.so.6 | grep GLIBCXX

确实没有 那几个GLIBCXX_3.4.N

26.顺着gcc安装路径,找到了新的libstdc++:

strings /usr/local/lib64/libstdc++.so.6.0.22|grep GLIBCXX

27.这里该有的都有了,把这份软链到正确的地方:

要root权限

cp /usr/local/lib64/libstdc++.so.6.0.22 /usr/lib64/

cd /usr/lib64

rm  -rf libstdc++.so.6

ln -s libstdc++s0.6.0.22 libstdc++.so.6

ll libstdc*

 

28. ./bootstrap

29.gmake

30.make install

要root权限

make install

31.cmake --version


 

 32. 进入build目录,cmake..

cd ~/libwebsockets/build

cmake ..

33. 不知道是不是缺少opsenssl库,但肯定缺少openssl-devel库,openssl库编译时依赖openssl-devel库,之所以说不缺定是不是缺少openssl库,因为我一起update了,所以不知道是不是也缺这个,另外,在 ubuntu系统中,是叫libssl-dev库,解bug时,没有注意,导致花了20分钟

yum -y install openssl

yum -y install openssl-devel

34. 进入build目录,再次cmake..

cd ~/libwebsockets/build

cmake ..

 

35. make

 


2.libwebsockets实现简易http服务器

https://blog.csdn.net/u013780605/article/details/79489193

1、填充服务器创建需要的参数

lws_context_creation_info是创建服务器句柄时用来定制服务器信息的结构体,所以我们首先需要填充该结构体。该结构体的定义如下。

/*这里只列出我们常用的成员,注释很详细,不做过多解释*/
struct lws_context_creation_info {
    int port;
    /**< VHOST: Port to listen on. Use CONTEXT_PORT_NO_LISTEN to suppress
     * listening for a client. Use CONTEXT_PORT_NO_LISTEN_SERVER if you are
     * writing a server but you are using ref sock-adopt instead of the
     * built-in listener  

监听端口。使用CONTEXT_PORT_NO_LISTEN禁止侦听客户端。如果您正在编写一个服务器,但您使用的是ref sock-plus而不是内置的侦听器,请使用            CONTEXT_PORT_NO_TEST_SERVER

       */
    const char *iface;
    /**< VHOST: NULL to bind the listen socket to all interfaces, or the
     * interface name, eg, "eth2"
     * If options specifies LWS_SERVER_OPTION_UNIX_SOCK, this member is
     * the pathname of a UNIX domain socket. you can use the UNIX domain
     * sockets in abstract namespace, by prepending an at symbol to the
     * socket name.

空,用于将侦听套接字绑定到所有接口或接口名称(例如,“eth2”)。
如果选项指定LWS_SERVER_OPTION_UNIX_SOCK,则此成员是UNIX域套接字的路径名。您可以在抽象命名空间中使用UNIX域套接字,方法是在套接字名称前添加at符号。

*/
    const struct lws_protocols *protocols;
    /**< VHOST: Array of structures listing supported protocols and a protocol-
     * specific callback for each one.  The list is ended with an
     * entry that has a NULL callback pointer.

一组结构,列出支持的协议和每个协议特定的回调。列表以具有空回调指针的项结束。

*/
    const struct lws_extension *extensions;
    /**< VHOST: NULL or array of lws_extension structs listing the
     * extensions this context supports.

Lws_Extension结构的空或数组,列出此上下文支持的扩展

     */
    const char *log_filepath;
    /**< VHOST: filepath to append logs to... this is opened before
     *      any dropping of initial privileges

要附加日志的文件路径.这是在任何初始特权被放弃之前打开的。

    */
    const struct lws_http_mount *mounts;
    /**< VHOST: optional linked list of mounts for this vhost 此vhost的可选装载链接列表*/

        ...
};
protocols用来指明该服务器可以处理的协议类型,以数组的形式提供并NULL作为数组结尾,如果不指定则默认使用http协议。

mounts用来设置与http服务器相关的参数,比如主机路径、URL路径、默认的主页文件等等。我们在这里初始化如下:

static const struct lws_http_mount mount = {
        /* .mount_next */               NULL,           /* linked-list "next" */
        /* .mountpoint */               "/",            /* mountpoint URL */
        /* .origin */                   ".",            /* serve from dir */
        /* .def */                      "index.html",   /* default filename */
        /* .protocol */                 NULL,
        /* .cgienv */                   NULL,
        /* .extra_mimetypes */          NULL,
        /* .interpret */                NULL,
        /* .cgi_timeout */              0,
        /* .cache_max_age */            0,
        /* .auth_mask */                0,
        /* .cache_reusable */           0,
        /* .cache_revalidate */         0,
        /* .cache_intermediaries */     0,
        /* .origin_protocol */          LWSMPRO_FILE,   /* files in a dir */
        /* .mountpoint_len */           1,              /* char count */
        /* .basic_auth_login_file */    NULL,
    };
struct lws_context_creation_info info;

/*初始化内存*/ 

memset(&info, 0, sizeof info);

info.port = 7681; 

info.mounts = &mount;

2、创建服务器句柄

调用的函数为:LWS_VISIBLE LWS_EXTERN struct lws_context* lws_create_context(struct lws_context_creation_info *info)   

当创建失败时,将会返回NULL

 struct lws_context *context;
 context = lws_create_context(&info);

3、运行服务器

 共有4个函数可以执行运行服务器,具体的介绍可以参见 api,这里我们使用第1个函数。

/*
 * context: 服务器句柄;
 * timeout_ms: 等待超时时间,即没有找到需要处理的连接需要等待的时间,为0则立即返回;
 * pollfd: poll结构;
 * tsi: 线程索引,默认为0;
 */

int lws_service (struct lws_context *context, int timeout_ms)
int lws_service_fd (struct lws_context *context, struct lws_pollfd *pollfd)
int lws_service_fd_tsi (struct lws_context *context, struct lws_pollfd *pollfd, int tsi)
int lws_service_tsi (struct lws_context *context, int timeout_ms, int tsi)      

 直接调用lws_service即可:

/*设置超时时间为1000ms*/
lws_service(context, 1000);

4、整体代码

/*
 * lws-minimal-http-server
 *
 * Copyright (C) 2018 Andy Green <andy@warmcat.com>
 * 版权所有(C)2018年AndyGreen<;Andy@palcat.com>;
 *
 * This file is made available under the Creative Commons CC0 1.0
 * Universal Public Domain Dedication.
 * 此文件在CreativeCommonsCC01.0通用公共域奉献下提供。
 *
 * This demonstrates the most minimal http server you can make with lws.
 * 这演示了使用LWS可以创建的最小http服务器。
 *
 * To keep it simple, it serves stuff in the directory it was started in.
 * You can change that by changing mount.origin
 * 为了简单起见,它在启动时所在的目录中提供服务。
 * 您可以通过更改mount t.Original来改变这一点。
 */

#include <libwebsockets.h>
#include <string.h>
#include <signal.h>

static int interrupted;

static const struct lws_http_mount mount = {
    /* .mount_next */       NULL,       /* linked-list "next" */
    /* .mountpoint */       "/",        /* mountpoint URL */
    /* .origin */           ".",        /* serve from dir */
    /* .def */          "index.html",   /* default filename */
    /* .protocol */         NULL,
    /* .cgienv */           NULL,
    /* .extra_mimetypes */      NULL,
    /* .interpret */        NULL,
    /* .cgi_timeout */      0,
    /* .cache_max_age */        0,
    /* .auth_mask */        0,
    /* .cache_reusable */       0,
    /* .cache_revalidate */     0,
    /* .cache_intermediaries */ 0,
    /* .origin_protocol */      LWSMPRO_FILE,   /* files in a dir */
    /* .mountpoint_len */       1,      /* char count */
    /* .basic_auth_login_file */    NULL,
};

void sigint_handler(int sig)
{
    interrupted = 1;
}

int main(int argc, char **argv)
{
    struct lws_context_creation_info info;
    struct lws_context *context;
    int n = 0;

    signal(SIGINT, sigint_handler);

    memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
    info.port = 7681;
    info.mounts = &mount;

    lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_USER
            /* | LLL_INFO */ /* | LLL_DEBUG */, NULL);

    lwsl_user("LWS minimal http server | visit http://localhost:7681n");

    context = lws_create_context(&info);
    if (!context) {
        lwsl_err("lws init failedn");
        return 1;
    }

    while (n >= 0 && !interrupted)
        n = lws_service(context, 1000);

    lws_context_destroy(context);

    return 0;
}

3.实现简易websocket服务器

https://blog.csdn.net/u013780605/article/details/79489197

实现websocket服务器本身也是libwebsockets库的初衷,本篇博客将介绍如何利用libwebsockets库来实现一个简单的ws服务器,即websocket服务器

1、添加websocket协议

这里创建服务器句柄的流程与http一致,需要修改的地方只有在创建服务器时传入的协议数组

struct lws_context_creation_info info;
struct lws_context *context;

static struct lws_protocols protocols[] =
{
    /*http服务器库中已做实现,直接使用lws_callback_http_dummy即可*/
    { "http", lws_callback_http_dummy, 0, 0 },
    LWS_PLUGIN_PROTOCOL_MINIMAL,
    { NULL, NULL, 0, 0 } /* 结束标志 */
};


    /*初始化内存*/
    memset(&info, 0, sizeof info);

    /*设置服务器端口*/
    info.port = 7681;

    /*设置http服务器的配置*/
    info.mounts = &mount;

    /*添加协议*/
    info.protocols = protocols;

    ...

struct lws_protocols的结构如下 :

struct lws_protocols {

    /*协议名称*/
    const char *name;

    /*服务回调,协议事件处理*/
    lws_callback_function *callback;

    /*服务建立和断开时申请内存大小,也是callback中user的内存*/
    size_t per_session_data_size;

    /*接收缓存区大小*/
    size_t rx_buffer_size;

    /*协议id,可以用来区分协议*/
    unsigned int id;

    /*自定义数据*/
    void *user; 

    /*发送缓存大小,为0则与rx_buffer_size相同*/
    size_t tx_packet_size;
};

 这里我们重点关注的是callback成员,它是一个lws_callback_function类型的函数指针,协议的的数据交互处理都会使用该回调函数。该回调函数的原型是

/*
 * wsi: 连接的websocket的实例
 * reason: 回调的原因
 * user:用户自定的数据,数据大小为per_session_data_size,需在连接初始化时申请内存
 * in: 回调的传入数据
 * len: in指向的内存大小
 */
typedef int
lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason, 
    void *user, void *in, size_t len);

 其中常用的reason值如下:

 /*协议初始化,只调用一次*/ 
    LWS_CALLBACK_PROTOCOL_INIT         

    /*连接已建立*/     
    LWS_CALLBACK_ESTABLISHED

    /*连接关闭*/
    LWS_CALLBACK_CLOSED

    /*可写*/
    LWS_CALLBACK_SERVER_WRITEABLE

    /*有数据到来*/
    LWS_CALLBACK_RECEIVE

 2、websocket服务器实例

下面我们以官方的一个例子来说明如何写回调函数。

这里我们将实现一个简单的聊天室,即当一个页面发送消息时,所有的连接的页面都会收到该消息。

(1) 服务器结构体

struct per_vhost_data__minimal 
{        
        /*服务器,可由vhost与protocol获取该结构体*/
        struct lws_vhost *vhost;

        /*使用的协议*/
        const struct lws_protocols *protocol;

        /*客户端链表*/
        struct per_session_data__minimal *pss_list;

        /*接收到的消息,缓存大小为一条数据*/
        struct msg amsg;

        /*当前消息编号,用来同步所有客户端的消息*/
        int current; 
};

 (2) 客户端的结构体

struct per_session_data__minimal 
{
        /*下一个客户端结点*/
        struct per_session_data__minimal *pss_list;

        /*客户端连接句柄*/
        struct lws *wsi;

        /*当前接收到的消息编号*/
        int last; 
};

(3) 消息结构

struct msg 
{
        /*内存地址*/
        void *payload;

        /*大小*/ 
        size_t len;
};

 整体代码如下:


/*消息释放*/
static void 
__minimal_destroy_message(void *_msg)
{
    struct msg *msg = _msg;

    free(msg->payload);
    msg->payload = NULL;
    msg->len = 0;
}

/*回调函数*/
static int
callback_minimal(struct lws *wsi, enum lws_callback_reasons reason,
            void *user, void *in, size_t len)
{
    /*获取客户端结构*/
    struct per_session_data__minimal **ppss, *pss =
            (struct per_session_data__minimal *)user;

    /*由vhost与protocol还原lws_protocol_vh_priv_zalloc申请的结构*/    
    struct per_vhost_data__minimal *vhd =
            (struct per_vhost_data__minimal *)
            lws_protocol_vh_priv_get(lws_get_vhost(wsi),
                    lws_get_protocol(wsi));
    int m;

    switch (reason) {

    /*初始化*/
    case LWS_CALLBACK_PROTOCOL_INIT:

            /*申请内存*/
            vhd = lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),
                lws_get_protocol(wsi),
                sizeof(struct per_vhost_data__minimal));
            vhd->protocol = lws_get_protocol(wsi);
            vhd->vhost = lws_get_vhost(wsi);

            break;

    /*建立连接,将客户端放入客户端链表*/
    case LWS_CALLBACK_ESTABLISHED:
        pss->pss_list = vhd->pss_list;
        vhd->pss_list = pss;
        pss->wsi = wsi;
        pss->last = vhd->current;
        break;

    /*连接关闭,将客户端从链表中移除*/
    case LWS_CALLBACK_CLOSED:

        /*遍历客户端链表*/
        lws_start_foreach_llp(struct per_session_data__minimal **,
                      ppss, vhd->pss_list) {
            if (*ppss == pss) {
                *ppss = pss->pss_list;
                break;
            }
        } lws_end_foreach_llp(ppss, pss_list);
        break;

    /*客户端可写*/
    case LWS_CALLBACK_SERVER_WRITEABLE:
        if (!vhd->amsg.payload)
            break;

        if (pss->last == vhd->current)
            break;

        /* notice we allowed for LWS_PRE in the payload already */
        m = lws_write(wsi, vhd->amsg.payload + LWS_PRE, vhd->amsg.len,
                  LWS_WRITE_TEXT);
        if (m < vhd->amsg.len) {
            lwsl_err("ERROR %d writing to di socketn", n);
            return -1;
        }

        pss->last = vhd->current;
        break;

    /*客户端收到数据*/
    case LWS_CALLBACK_RECEIVE:
        if (vhd->amsg.payload)
            __minimal_destroy_message(&vhd->amsg);

        vhd->amsg.len = len;

        /* notice we over-allocate by LWS_PRE */
        vhd->amsg.payload = malloc(LWS_PRE + len);
        if (!vhd->amsg.payload) {
            lwsl_user("OOM: droppingn");
            break;
        }

        memcpy((char *)vhd->amsg.payload + LWS_PRE, in, len);
        vhd->current++;

        /*
         *遍历所有的客户端,将数据放入写入回调
         */
        lws_start_foreach_llp(struct per_session_data__minimal **,
                      ppss, vhd->pss_list) {
            lws_callback_on_writable((*ppss)->wsi);
        } lws_end_foreach_llp(ppss, pss_list);
        break;

    default:
        break;
    }

    return 0;
}

#define LWS_PLUGIN_PROTOCOL_MINIMAL 
    { 
        "lws-minimal", 
        callback_minimal, 
        sizeof(struct per_session_data__minimal), 
        128, 
        0, NULL, 0 
    }

4.websocket介绍

什么是WebSocket?看过html5的同学都知道,WebSocket protocol 是HTML5一种新的协议。它是实现了浏览器与服务器全双工通信(full-duplex)。HTML5定义了WebSocket协议,能更好的节省服务器资源和带宽并达到实时通讯。现在我们来探讨一下html5的WebSocket概念

HTML5作为下一代WEB标准,拥有许多引人注目的新特性,如Canvas、本地存储、多媒体编程接口、WebSocket 等等。今天我们就来看看具有“Web TCP”之称的WebSocket。

WebSocket的出现是基于Web应用的实时性需要而产生的。这种实时的Web应用大家应该不陌生,在生活中都应该用到过,比如新浪微博的评论、私信的通知,腾讯的WebQQ等。让我们来回顾下实时 Web 应用的窘境吧。

在WebSocket出现之前,一般通过两种方式来实现Web实时用:轮询机制流技术;其中轮询有不同的轮询,还有一种叫Comet的长轮询

轮询:这是最早的一种实现实时 Web 应用的方案。客户端以一定的时间间隔向服务端发出请求,以频繁请求的方式来保持客户端和服务器端的同步。这种同步方案的缺点是,当客户端以固定频率向服务 器发起请求的时候,服务器端的数据可能并没有更新,这样会带来很多无谓的网络传输,所以这是一种非常低效的实时方案。

长轮询:是对定时轮询的改进和提高,目地是为了降低无效的网络传输。当服务器端没有数据更新的时候,连接会保持一段时间周期直到数据或状态改变或者 时间过期,通过这种机制来减少无效的客户端和服务器间的交互。当然,如果服务端的数据变更非常频繁的话,这种机制和定时轮询比较起来没有本质上的性能的提 高。

:常就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服务 器端的连接不过期。通过这种机制可以将服务器端的信息源源不断地推向客户端。这种机制在用户体验上有一点问题,需要针对不同的浏览器设计不同的方案来改进 用户体验,同时这种机制在并发比较大的情况下,对服务器端的资源是一个极大的考验。

上述方式其实并不是真正的实时技术,只是使用了一种技巧来实现的模拟实时。在每次客户端和服务器端交互的时候都是一次 HTTP 的请求和应答的过程,而每一次的 HTTP 请求和应答都带有完整的 HTTP 头信息,这就增加了每次传输的数据量。但这些方式最痛苦的是开发人员,因为不论客户端还是服务器端的实现都很复杂,为了模拟比较真实的实时效果,开发人员 往往需要构造两个HTTP连接来模拟客户端和服务器之间的双向通讯,一个连接用来处理客户端到服务器端的数据传输,一个连接用来处理服务器端到客户端的数 据传输,这不可避免地增加了编程实现的复杂度,也增加了服务器端的负载,制约了应用系统的扩展性。


基于上述弊端,实现Web实时应用的技术出现了,WebSocket通过浏览器提供的API真正实现了具备像C/S架构下的桌面系统的实时通讯能 力。其原理是使用JavaScript调用浏览器的API发出一个WebSocket请求至服务器,经过一次握手,和服务器建立了TCP通讯,因为它本质 上是一个TCP连接,所以数据传输的稳定性强和数据传输量比较小。
 

WebSocket 协议

WebSocket 协议本质上是一个基于 TCP 的协议。为了建立一个 WebSocket 连接,客户端浏览器首先要向服务器发起一个 HTTP 请求,这个请求和通常的 HTTP 请求不同,包含了一些附加头信息,其中附加头信息”Upgrade: WebSocket”表明这是一个申请协议升级的 HTTP 请求,服务器端解析这些附加的头信息然后产生应答信息返回给客户端,客户端和服务器端的 WebSocket 连接就建立起来了,双方就可以通过这个连接通道自由的传递信息,并且这个连接会持续存在直到客户端或者服务器端的某一方主动的关闭连接。

下面我们来详细介绍一下 WebSocket 协议,由于这个协议目前还是处于草案阶段,版本的变化比较快,我们选择目前最新的 draft-ietf-hybi-thewebsocketprotocol-17 版本来描述 WebSocket 协议。因为这个版本目前在一些主流的浏览器上比如 Chrome,、FireFox、Opera 上都得到比较好的支持。通过描述可以看到握手协议

客户端发到服务器的内容:

    GET /chat HTTP/1.1
    Host: server.example.com
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    Origin: http://example.com
    Sec-WebSocket-Protocol: chat, superchat
    Sec-WebSocket-Version: 13

从服务器到客户端的内容: 

    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
    Sec-WebSocket-Protocol: chat

这些请求和通常的 HTTP 请求很相似,但是其中有些内容是和 WebSocket 协议密切相关的。我们需要简单介绍一下这些请求和应答信息,”Upgrade:WebSocket”表示这是一个特殊的 HTTP 请求,请求的目的就是要将客户端和服务器端的通讯协议从 HTTP 协议升级到 WebSocket 协议。其中客户端的Sec-WebSocket-Key和服务器端的Sec-WebSocket-Accept就是重要的握手认证信息了,这些内容将在服 务器端实现的博文中讲解。
 

关键是服务器端Sec-WebSocket-Accept,它是根据Sec-WebSocket-Key计算出来的:
取出Sec-WebSocket-Key,与一个magic string “258EAFA5-E914-47DA-95CA-C5AB0DC85B11” 连接成一个新的key串;
将新的key串SHA1编码,生成一个由多组两位16进制数构成的加密串;
把加密串进行base64编码生成最终的key,这个key就是Sec-WebSocket-Key;


5.虚拟机安装

https://blog.csdn.net/qq_37546891/article/details/80482031

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/xiaotian_muzi/article/details/89786075
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-07 03:24:27
  • 阅读 ( 2438 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢