c++ libwebsocket库应用开发
WebSocket是一種在單個TCP連接上進行全雙工通信的協議。允許服務端主動向客戶端推送數據。在WebSocket API中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創建持久性的連接,并進行雙向數據傳輸。
一、參考網址:
libwebsockets官網: ?https://libwebsockets.org/
libwebsockets的API:https://libwebsockets.org/lws-api-doc-master/html/modules.html
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?https://libwebsockets.org/libwebsockets-api-doc.html
cmake?去除openssl庫依賴.vs2010編譯.?
建立雙工通道,接下來就可以進行收發數據, 當連接成功之后,通過不斷詢問service?是否有回調事件,來處理對應的回調事件.?
// ConSoleWebS_Test.cpp : 定義控制臺應用程序的入口點。
 //
#include "stdafx.h"
 // Consolelibwebs.cpp : 此文件包含 "main" 函數。程序執行將在此處開始并結束。
 //
#include <iostream>
 #include "include/libwebsockets.h"
 #include <signal.h>
 #include <string.h>
 #include <map>
 using namespace std;
 map<long,string>map_wsi_token;// 存wsi指針為key, token為字符串
 static volatile int exit_sig = 0;
 #define MAX_PAYLOAD_SIZE ?10 * 1024
void sighdl(int sig) {
 ? ? lwsl_notice("%d traped", sig);
 ? ? exit_sig = 1;
 }
/**
 ?* 會話上下文對象,結構根據需要自定義
 ?*/
 struct session_data {
 ? ? int msg_count;
 ? ? unsigned char buf[LWS_PRE + MAX_PAYLOAD_SIZE];
 ? ? int len;
 ? ? bool bin;
 ? ? bool fin;
 };
static int protocol_my_callback(struct lws* wsi, enum lws_callback_reasons reason, void* user, void* in, size_t len) {
 ? ??? ?
 ?? ?struct session_data* data = (struct session_data*)user;
 ? ? switch (reason) {
 ?? ?case LWS_CALLBACK_PROTOCOL_INIT:
 ?? ??? ?break;
 ?? ?case LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION: //這里的wsi中才有url內容
 ?? ??? ?{?? ??? ?
 ?? ??? ??? ?char content_length_str[200] = {0};
 ?? ??? ??? ?lws_hdr_copy(wsi,content_length_str,200,(lws_token_indexes)0);
 ?? ??? ??? ?//TODO: 獲取最新的mythread->GetNewToken(chartoken); 替換 a2abd43dfooepcxw
 ?? ??? ??? ?//.例如:
 ?? ??? ??? ?//char chartoken[100] = {0};
 ?? ??? ??? ?//mythread->GetNewToken(chartoken);
 ?? ??? ??? ?//if(strstr(content_length_str,chartoken) != NULL)
 ?? ??? ??? ?//{
 ?? ??? ??? ?//?? ?map_wsi_token.insert(pair<long,string>(long(wsi),string(chartoken)));
 ?? ??? ??? ?//}
 ?? ??? ??? ?//else
 ?? ??? ??? ?//?? ?return -1;
 ?? ??? ?}
 ?? ??? ?break;
 ?? ?case LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED:
 ?? ??? ?break;
 ?? ?case LWS_CALLBACK_FILTER_NETWORK_CONNECTION:
 ?? ??? ?break;
 ?? ?case LWS_CALLBACK_WSI_CREATE:
 ?? ??? ?break;
 ?? ?case LWS_CALLBACK_HTTP:
 ?? ??? ?break;
 ?? ?case LWS_CALLBACK_ADD_HEADERS:
 ?? ??? ?break;
 ?? ?case LWS_CALLBACK_FILTER_HTTP_CONNECTION:
 ?? ??? ?break;
 ? ? case LWS_CALLBACK_ESTABLISHED: ? ? ? // 當服務器和客戶端完成握手后
 ? ? ? ? printf("Client connect!\n");
 ? ? ? ? break;
 ?? ?case LWS_CALLBACK_SESSION_INFO:
 ?? ??? ?break;
 ? ? case LWS_CALLBACK_RECEIVE: ? ? ? ? ? // 當接收到客戶端發來的幀以后
 ?? ??? ?{
 ?? ??? ??? ?map<long,string>::iterator iter = map_wsi_token.find(long(wsi));
 ?? ??? ??? ?if(iter != map_wsi_token.end())
 ?? ??? ??? ?{
 ?? ??? ??? ??? ?//TODO: 獲取最新的mythread->gettoken(char); 替換 a2abd43dfooepcxw
 ?? ??? ??? ??? ?string strtoken = iter->second;
 ?? ??? ??? ??? ?
 ?? ??? ??? ??? ?if(strtoken.find("a2abd43dfooepcxw") >= -1)
 ?? ??? ??? ??? ?{
 ?? ??? ??? ??? ??? ?return -1;
 ?? ??? ??? ??? ?}
 ?? ??? ??? ?}
 ?? ??? ??? ?else
 ?? ??? ??? ?{
 ?? ??? ??? ??? ?return -1;
 ?? ??? ??? ?}
?? ??? ??? ?// 判斷是否最后一幀
 ?? ??? ??? ?data->fin = lws_is_final_fragment(wsi);
 ?? ??? ??? ?// 判斷是否二進制消息
 ?? ??? ??? ?data->bin = lws_frame_is_binary(wsi);
 ?? ??? ??? ?// 對服務器的接收端進行流量控制,如果來不及處理,可以控制之
 ?? ??? ??? ?// 下面的調用禁止在此連接上接收數據
 ?? ??? ??? ?lws_rx_flow_control(wsi, 0);
?? ??? ??? ?// 業務處理部分,為了實現Echo服務器,把客戶端數據保存起來
 ?? ??? ??? ?memcpy(&data->buf[LWS_PRE], in, len);
 ?? ??? ??? ?data->len = len;
 ?? ??? ??? ?printf("recvied message:%s\n", in);
?? ??? ??? ?// 需要給客戶端應答時,觸發一次寫回調
 ?? ??? ??? ?lws_callback_on_writable(wsi);
 ?? ??? ?}
 ? ? ? ? break;
 ? ? case LWS_CALLBACK_SERVER_WRITEABLE: ? // 當此連接可寫時
 ?? ??? ?{
 ?? ??? ??? ?lws_write(wsi, &data->buf[LWS_PRE], data->len, LWS_WRITE_TEXT);
 ?? ??? ??? ?// 下面的調用允許在此連接上接收數據
 ?? ??? ??? ?lws_rx_flow_control(wsi, 1);
 ?? ??? ?}
? ? ? ? break;
 ?? ?case LWS_CALLBACK_LOCK_POLL:
 ?? ?case LWS_CALLBACK_UNLOCK_POLL:
 ?? ??? ?break;
 ?? ?case LWS_CALLBACK_WS_PEER_INITIATED_CLOSE:
 ?? ??? ?map<long,string>::iterator iter = map_wsi_token.find(long(wsi));
 ?? ??? ?if(iter != map_wsi_token.end())
 ?? ??? ?{
 ?? ??? ??? ?map_wsi_token.erase(iter);
 ?? ??? ?}
 ?? ??? ?break;
 ? ? }
 ? ? // 回調函數最終要返回0,否則無法創建服務器
 ? ? return 0;
 }
/**
 ?* 支持的WebSocket子協議數組
 ?* 子協議即JavaScript客戶端WebSocket(url, protocols)第2參數數組的元素
 ?* 你需要為每種協議提供回調函數
 ?*/
 struct lws_protocols protocols[] = {
 ?? ?{
 ? ? ? ? //協議名稱,協議回調,接收緩沖區大小
 ? ? ? ? "http", protocol_my_callback, sizeof(struct session_data), MAX_PAYLOAD_SIZE,
 ? ? },
 ? ? {
 ? ? ? ? //協議名稱,協議回調,接收緩沖區大小
 ? ? ? ? "ws", protocol_my_callback, sizeof(struct session_data), MAX_PAYLOAD_SIZE,
 ? ? },
 ? ? {
? ? ? ? NULL, NULL, ? 0 // 最后一個元素固定為此格式
 ? ? }
 };
int _tmain(int argc, _TCHAR* argv[])
 {
 ? ? // 信號處理函數
 ? ? signal(SIGTERM, sighdl);
? ? struct lws_context_creation_info ctx_info = { 0 };
 ? ? ctx_info.port = 9002;
 ? ? ctx_info.iface = NULL; // 在所有網絡接口上監聽
 ? ? ctx_info.protocols = protocols;
 ? ? ctx_info.gid = -1;
 ? ? ctx_info.uid = -1;
 ? ? ctx_info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
? ?// ctx_info.ssl_ca_filepath = "../ca/ca-cert.pem";
 ? // ?ctx_info.ssl_cert_filepath = "./server-cert.pem";
 ? ?// ctx_info.ssl_private_key_filepath = "./server-key.pem";
 ? // ?ctx_info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
 ? ? //ctx_info.options |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;
? ? struct lws_context* context = lws_create_context(&ctx_info);
 ? ? while (!exit_sig) {
 ? ? ? ? lws_service(context, 1000);
 ? ? }
 ? ? lws_context_destroy(context);
? ? return 0;
 }
 ?
總結
以上是生活随笔為你收集整理的c++ libwebsocket库应用开发的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 使用VS Code远程连接服务器,在VS
- 下一篇: ORACLE ERP 系统架构与应用实践
