日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

【C++】libwebsockets库的简易教程

發布時間:2023/12/20 c/c++ 58 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【C++】libwebsockets库的简易教程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

說在前面

最近很長一段時間,都有在嵌入式上進行websocket通信的需求。
查了很多資料,現在C++可用的ws第三方庫不多,尤其是在較老的嵌入式開發環境中,既要支持C99和SSL,又需要輕量級不依賴第三方庫,基本上就只剩下libwebsockets這個庫了。
但是libwebsockets庫是純C開發,沒有C++的特性,所以很多邏輯非常抽象,設計思路也很詭異,與之前接觸的很多三方模塊差異太大。我扒了源碼的demo,又從官方git、wiki上找了一點資料,才勉強搞清楚了一個簡單的ws客戶端的大致生命周期流程,寫了個簡單的client端


編譯libwebsockets

  • [github地址]https://github.com/warmcat/libwebsockets
  • 使用版本 v4.0-stable
  • 安裝cmake
    libwebsockets的編譯部署是基于cmake,所以需要事先安裝cmake,可以從源或者cmake官網下載到二進制文件或者源碼 [cmake官網]https://cmake.org

    • x84 Linux ,使用相關命令從源里直接獲取cmake二進制包。例如Ubuntu:sudo apt-get install cmake
    • 如果是嵌入式arm的Linux,一般推薦下載cmake源碼自行編譯(本文不再贅述編譯部署方式)
    • win系統,直接下載msi/exe安裝包,一鍵安裝即可
  • 編譯
    以Linux為例

    • 進入libwebsockets源碼目錄
    • 創建build目錄mkdir build
    • cmake編譯cd build cmake .. make
    • 在cmake … 命令執行過程中,會檢測系統的openssl模塊
      如果需要使用wss,則需要提前安裝openssl,Ubuntu可以直接__sudo apt-get install libssl-dev__;
      或者下載openssl源碼安裝,并設置OPENSSL_ROOT_DIR環境變量,來指定openssl的根目錄位置__export OPENSSL_ROOT_DIR=[openssl的目錄]__
      如果不需要wss,直接忽略cmake過程中的OPENSSL NOT FOUND警告即可
    • make之后,會在build目錄下生成include目錄和lib目錄,這個就是libwebsockets的頭文件和庫文件。


  • libwebsockets的周期流程

    • 核心思想:
  • 回調函數:libwebsockets的回調函數(lws_callbacks.h)

    typedef int lws_callback_function(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);

    lws在初始化配置時,需要定一個回調函數,lws會通過該回調函數返回給開發者當前的所有狀態:初始化、連接建立、連接失敗、數據讀寫等等,而狀態類型通過枚舉reason來反饋。

  • 消息循環
    當開發者將所有的參數配置結束后,需要循環調用lws_service,來反復進行lws內部邏輯并觸發回調函數。這個循環就是消息循環。

    • 基本流程:
    • 處理協議(定義回調函數)
    • 配置lws_context_creation_info參數
    • 創建lws_context
    • 配置連接信息lws_client_connect_info
    • 進入消息循環
    • 通過回調函數實時獲取ws狀態并進行下一步操作(發送、接受、斷開、異常控制)

    簡易客戶端代碼

    范例代碼

    #include <pthread.h> #include <iostream> #include <string.h> #include <string> #include <libwebsockets.h>static lws *wsi = NULL; static bool established = false; static bool isBreak = false; static bool stop = false;//分析ws地址 //parameters : //@ _url [in]完整的url //@ _protocol [out]協議字符串 ws/wss //@ _host [out]主機地址 //@ _port [out]端口,如果沒有端口號,返回-1 //@ _path [out]url的path部分 int UnmarshalURL(const char *_url, std::string &_protocol, std::string &_host, int &_port, std::string &path) {std::string url(_url);int pslash = url.find("//", 0);if (pslash >= 0){_protocol = url.substr(0, pslash - 1);url = url.substr(pslash + 2);}pslash = url.find(':');if (pslash < 0){//沒有端口號_port = -1;pslash = url.find('/', 0);if (pslash < 0){//沒有path_host = url;}else{//有path_host = url.substr(0, pslash);path = url.substr(pslash);}}else{//有端口號_host = url.substr(0, pslash);url = url.substr(pslash + 1);pslash = url.find('/', 0);if (pslash < 0){//沒有path_port = atoi(url.c_str());}else{//有path_port = atoi(url.substr(0, pslash).c_str());path = url.substr(pslash);}}return 0; }//記錄接收10次服務器返回 static int recvSum = 0; // lws消息回調函數 int ws_callback(lws *_wsi, enum lws_callback_reasons _reasons, void *_user, void *_in, size_t _len) {printf("CALLBACK REASON: %d\n", _reasons);//發送或者接受buffer,建議使用棧區的局部變量,lws會自己釋放相關內存//如果使用堆區自定義內存空間,可能會導致內存泄漏或者指針越界char buffer[2560];memset(buffer, 0, 2560);switch (_reasons){case LWS_CALLBACK_CLIENT_ESTABLISHED://連接成功時,會觸發此reasonprintf("established\n");//調用一次lws_callback_on_writeable,會觸發一次callback的LWS_CALLBACK_CLIENT_WRITEABLE,之后可進行一次發送數據操作lws_callback_on_writable(_wsi);break;case LWS_CALLBACK_CLIENT_CLOSED:// 客戶端主動斷開、服務端斷開都會觸發此reasonisBreak = true; // ws關閉,發出消息,退出消息循環printf("ws closed\n");break;case LWS_CALLBACK_CLIENT_CONNECTION_ERROR://連接失敗、異常printf("connect error\n");break;case LWS_CALLBACK_CLIENT_RECEIVE://獲取到服務端的數據memcpy(buffer, _in, _len);printf("recv: %s\n", buffer);usleep(1 * 1000 * 1000);lws_callback_on_writable(_wsi);break;case LWS_CALLBACK_CLIENT_WRITEABLE://調用lws_callback_on_writeable,會觸發一次此reasonif (stop)break;recvSum++;if (recvSum >= 10){stop = true;printf("will close\n");//使用lws_close_reason來準備斷開連接的斷開信息lws_close_reason(_wsi, LWS_CLOSE_STATUS_GOINGAWAY, NULL, 0);//當callback中return非0 時,則會主動斷開websocketreturn -1;}sprintf(buffer, "send data %02d\0", recvSum);printf("%s\n", buffer);int len = lws_write(_wsi, buffer, strlen(buffer), LWS_WRITE_TEXT);printf("write len=%d\n", len);break;default:break;}return 0; }//程序輸入參數 范例 //exe ws://172.31.234.19:4455/ws/demo //exe wss://www.unruly.online:3344/ws/demo int main(int argc, char **argv) {if (argc != 2){printf("cmd parameters error!\n");return -1;}char *url = argv[1];printf("des URL:%s\n", url);std::string protocol; //ws/wss協議std::string host; //主機IPint port; //端口std::string path; //path//解析URL的參數UnmarshalURL(url, protocol, host, port, path);bool ssl = protocol == "wss" ? true : false; //確認是否進行SSL加密//lws初始化階段struct lws_context_creation_info info; //websocket 配置參數struct lws_context *context; //websocket 連接上下文struct lws_client_connect_info ci; //websocket 連接信息//建議初始化全部置為0memset(&info, 0, sizeof(info));memset(&ci, 0, sizeof(ci));struct lws_protocols lwsprotocol[2];//ws處理協議初始化時,建議將所有內存空間置0memset(&lwsprotocol[0], 0, sizeof(lws_protocols));memset(&lwsprotocol[1], 0, sizeof(lws_protocols));lwsprotocol[0].name = "ws-client";lwsprotocol[0].callback = ws_callback; //設置回調函數lwsprotocol[0].user = NULL;lwsprotocol[0].tx_packet_size = 5120;lwsprotocol[0].rx_buffer_size = 5120;lwsprotocol[1].name = NULL;lwsprotocol[1].callback = NULL;info.protocols = lwsprotocol; //設置處理協議info.port = CONTEXT_PORT_NO_LISTEN; //作為ws客戶端,無需綁定端口//ws和wss的初始化配置不同info.options = ssl ? LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT : 0; //如果是wss,需要做全局SSL初始化context = lws_create_context(&info); //創建連接上下文if (context == NULL){printf("create context error\n");return -1;}//初始化連接信息ci.context = context; //設置上下文ci.address = host.c_str(); //設置目標主機IPci.port = port; //設置目標主機服務端口ci.path = path.c_str(); //設置目標主機服務PATHci.host = ci.address; //設置目標主機IPci.origin = ci.address; //設置目標主機IPci.pwsi = &wsi; //設置wsi句柄ci.userdata = NULL; //userdata 指針會傳遞給callback的user參數,一般用作自定義變量傳入ci.protocol = lwsprotocol[0].name;//ws/wss需要不同的配置ci.ssl_connection = ssl ? (LCCSCF_USE_SSL | LCCSCF_ALLOW_SELFSIGNED | LCCSCF_SKIP_SERVER_CERT_HOSTNAME_CHECK | LCCSCF_ALLOW_INSECURE) : 0;lws_client_connect_via_info(&ci); //使連接信息生效//進入消息循環while (!isBreak){lws_service(context, 500);}printf("ws disconnect\n");return 0; }

    libwebsockets也還在學習階段,代碼只實現了簡單的客戶端通信,如果有其他問題,可以評論,我會在空閑時間回復解答

    PS:
    libwebsockets的接口非常底層,很多邏輯需要自己封裝實現
    libwebsockets不是線程安全的庫,如果想要將其進行封裝為類,那么線程、信號量、鎖的控制一定要非常嚴謹

    總結

    以上是生活随笔為你收集整理的【C++】libwebsockets库的简易教程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 亚洲精品久久久久久久久久久 | 中文在线免费观看 | 亚洲国产av一区二区 | 免费av的网站 | 午夜影音 | 国产精品88 | 一区二区视频在线看 | 男人天堂999 | 少妇毛片一区二区三区粉嫩av | 欧美一区成人 | 污网站在线观看免费 | 午夜福利123 | 97精品久久 | 丰满人妻翻云覆雨呻吟视频 | 九九这里只有精品视频 | 青青草精品 | 大黑人交xxx极品hd | 桃色91| 国产宾馆实践打屁股91 | 亚洲色图 校园春色 | 水牛影视av一区二区免费 | 成人免费视频观看视频 | 丁香花免费高清完整在线播放 | 天堂在线中文字幕 | 欧美网站在线观看 | 黑人性视频 | 三级黄色片免费 | 欧美在线一区二区三区 | 国产精品无码专区av免费播放 | 国产第十页 | 日本亲与子乱ay中文 | 天天撸天天操 | 国产成人77亚洲精品www | 一区二区三区在线观看av | 国产成人精品av久久 | 17草在线| av片亚洲 | 免费不卡视频 | www.com毛片| 亚洲高清一区二区三区 | 亚洲黄色激情视频 | 激情黄色小视频 | 亚洲一区二区三区四区视频 | 69av导航| 一区二区三区视频 | 毛片.com | 青青草超碰在线 | 丰满人妻一区二区三区免费视频棣 | 国产主播福利在线 | 久久中文字幕高清 | 久久一级电影 | 成人调教视频 | 丁香花高清视频完整电影 | 亚洲av毛片一区二二区三三区 | 麻豆影视av| 人禽高h交 | 91亚洲精品久久久蜜桃网站 | 色噜噜狠狠一区二区三区果冻 | 久久亚洲av永久无码精品 | 涩涩视频网址 | aaa国产视频| 男人操女人动漫 | 国产日韩欧美在线观看视频 | 潘金莲一级淫片aaaaa武则天 | 奇米影视一区二区 | 四房婷婷| 热久久av | 欧美日韩一区二区三区69堂 | 精品少妇无码av无码专区 | 女同毛片一区二区三区 | 欧美3p在线观看 | 伊人色婷婷 | 肉色超薄丝袜脚交69xx | 欧美亚洲另类图片 | 亚洲人成色777777老人头 | 黄色三级免费网站 | 亚洲一级视频在线观看 | 好吊操免费视频 | 永久免费成人代码 | 亚洲一区二区三区观看 | 99精品区| 日本内谢少妇xxxxx少交 | 日本一品道 | 天天做天天爱天天爽综合网 | 欧美最黄视频 | 毛片基地在线观看 | 美女露出让男生揉的视频 | 91亚洲精品乱码久久久久久蜜桃 | 欧美性白人极品1819hd | 亚洲精品一区二区三区蜜桃 | yjizz视频网| 国产伦精品一区二区三区千人斩 | 国产盗摄一区二区三区在线 | 美日韩一二三区 | 成人h动漫精品一区二区器材 | 波多野结衣电车痴汉 | 亚洲一区二区三区四区 | 欧美日韩国产中文 | 美女操出白浆 |