目录

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端口。

访问该网址和端口即可查看最终的效果(不要使用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:7681\n");context = lws_create_context(&info);if (!context) {lwsl_err("lws init failed\n");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 socket\n", 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: dropping\n");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

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

  1. linux上安装telnet服务器:linux vmvare虚拟机 安装telnet redhat9

    linux上安装telnet服务器:linux vmvare虚拟机 安装telnet redhat9 参考:http://blog.sina.com.cn/s/blog_5688414b0100bhr ...

  2. Linux下MKL库的安装部署与使用,并利用cmake编译器调用MKL库去提升eigen库的计算速度

    文章目录 前言 一.MKL库的下载 二.MKL库的安装与配置 1.MKL库的安装与配置 2.代码测试 总结 前言 在用C/C++编写模型预测控制算法(MPC)的代码时候,由于预测步长和控制步长的设置较 ...

  3. python中安装一个第三方库的命令格式是-无法使用pip命令安装python第三方库的彻底解决方案...

    无法使用pip命令安装python第三方库的原因及解决方法 再dos中无法使用pip,命令主要是没有发现这个命令.我们先找到这个命令的位置,一般是在python里面的Scripts文件夹里面.我们可以 ...

  4. python安装成功第三方库但import出问题_解析pip安装第三方库但PyCharm中却无法识别的问题及PyCharm安装第三方库的方法教程...

    一.问题具体描述: 在cmd控制台 pip install xxxx 后并显示安装成功后,并且尝试用cmd 的python 中import xxxx ,没有显示异常,说明这个库是安装成功了的.(这里以 ...

  5. hp服务器下的虚拟机安装系统安装,hp 服务器安装linux系统安装

    hp 服务器安装linux系统安装 内容精选 换一换 该任务以"CentOS 7 64位"操作系统为例,指导用户安装Linux操作系统.由于镜像文件不同,安装步骤稍有不同,请根据实 ...

  6. vmesxi 虚拟服务器 黑苹果,ESXI虚拟机安装MacOS

    虚拟机上安装macos比物理机上安装限制少的多,也简单的多. 本文是在esxi6.7 update3版本上安装的Macos Catalina 10.15.6 .安装流程总的来说分三步, 是制作ISO虚 ...

  7. Anaconda 安装python第三方库的各类方法

    Anaconda 安装python第三方库的各类方法(已更新离线安装) 之前的文章讲了有关anaconda的一些介绍和安装,第三方源也介绍了,本文介绍Anaconda安装python第三发库的各类方法 ...

  8. python怎么查看安装了哪些库

    这里写目录标题 前言 方法1 方法2 前言 有时候我们在使用python的时候,想知道自己安装哪些了第三方库以及第三方库的版本,下面来介绍一下方法 方法1 我们可以通过命令提示符输入相关的命令进行查看 ...

  9. 虚拟机安装与配置(安装cent0S)

    一.为什么用虚拟机 1.老平台开发的软件,在当前系统下无法运行: 2.测试工作的需要,需要在一单独电脑上运行,而自己目前又没有现成的条件,只有借助虚拟机: 3.有些测试的工作在虚拟机上做,保持电脑系统 ...

最新文章

  1. 回顾2021,展望2022
  2. Spring 源码分析(四) ——MVC(一)Web 基础
  3. Android 8.0 (35)----Android8.0.0-r4的OTA升级流程
  4. SpringBoot整合kafka案例
  5. (一)操作系统基本概念(任哲版嵌入ucos和linux笔记)
  6. Spring cloud Gateway介绍
  7. MATLAB通过两点画三维直线(plot3)
  8. 综合布线系统工程设计规范GB50311-2007
  9. 少年群侠传服务器维护时间,少年群侠传开服表
  10. 金彩教育:如何提升店铺的信誉
  11. 苹果充电显示不支持此配件_水果手机充电时,显示不支持此配件时的应急处理小窍门...
  12. 360大战QQ演义之一:一场腾讯可能连底裤都输掉的战争!
  13. [HTML/CSS]Flex布局中space-evenly的兼容性
  14. 三十而立~2019年终总结
  15. 书写台灯哪种比较适合儿童?盘点护眼的儿童读写台灯推荐
  16. 【无标题】MobaXterm远程连接服务器跑深度学习
  17. 基于matlab的MRC最大合并比误码率仿真,包括维特比译码,MRC,中继
  18. 从零开始学数据分析之——《笨办法学Python》(习题27-36)
  19. 通达OA 尝试一下进行通达OA的培训
  20. 西软服务器linux,FOXHIS前台西软服务器端和客户端安装教程.pdf

热门文章

  1. 怎么使用focus插件制作动态图册
  2. 单片机在微型计算机系统中的作用,单片机在智能仪器仪表中的应用
  3. 拿命 3 天肝出来的计算机考研数据结构与算法复习笔记(超详细教程,更新中)
  4. 线特征LSD提取、LBD描述子匹配实现过程源码
  5. 爱前端邵山欢课程 node+angular+vue+react+webapp高级部分
  6. mysql aes_decrypt_MySQL如何使用AES_ENCRYPT()与AES_DECRYPT()进行加解密的示例
  7. 喜欢玩游戏又想做产品经理,所以我当了老师
  8. 如何选择ROS机器人平台进行SLAM导航入门:SLAM与ROS的关系
  9. 软考 信息系统项目管理师证书会过期吗?高项证书有效期
  10. 情从何起?脑来揭秘。