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
- 下一篇: 视频教程-QQ机器人--基于酷Q开发7精