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端口。
?訪問該網址和端口即可查看最終的效果(不要使用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 應用的方案??蛻舳艘砸欢ǖ臅r間間隔向服務端發出請求,以頻繁請求的方式來保持客戶端和服務器端的同步。這種同步方案的缺點是,當客戶端以固定頻率向服務 器發起請求的時候,服務器端的數據可能并沒有更新,這樣會帶來很多無謂的網絡傳輸,所以這是一種非常低效的實時方案。
長輪詢:是對定時輪詢的改進和提高,目地是為了降低無效的網絡傳輸。當服務器端沒有數據更新的時候,連接會保持一段時間周期直到數據或狀態改變或者 時間過期,通過這種機制來減少無效的客戶端和服務器間的交互。當然,如果服務端的數據變更非常頻繁的話,這種機制和定時輪詢比較起來沒有本質上的性能的提 高。
流:常就是在客戶端的頁面使用一個隱藏的窗口向服務端發出一個長連接的請求。服務器端接到這個請求后作出回應并不斷更新連接狀態以保證客戶端和服務 器端的連接不過期。通過這種機制可以將服務器端的信息源源不斷地推向客戶端。這種機制在用戶體驗上有一點問題,需要針對不同的瀏覽器設計不同的方案來改進 用戶體驗,同時這種機制在并發比較大的情況下,對服務器端的資源是一個極大的考驗。
上述方式其實并不是真正的實時技術,只是使用了一種技巧來實現的模擬實時。在每次客戶端和服務器端交互的時候都是一次 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服务器,虚拟机安装)的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: 嵌入式开发环境搭建
 - 下一篇: qemu的详细资料大全(入门必看!!!)