c++ libwebsocket库应用开发2
1.向web端發送二進制數據與文本數據時注意?
?//lws_write(wsi, data->buf+LWS_PRE, isz, LWS_WRITE_BINARY);
?//lws_write(wsi, data->buf+LWS_PRE, isz, LWS_WRITE_TEXT);
?2.使用信號量?一生產者一消費者同步
3.未嘗試將senddata數據直接拷貝到data->buf+ LWS_PRE后面區域, 而不借助成員變量.?
map<long,string>map_wsi_token;// 存wsi指針為key, token為字符串
static volatile int exit_sig = 0;
#define MAX_PAYLOAD_SIZE ?13 * 1024
void sighdl(int sig) {
? ? lwsl_notice("%d traped", sig);
? ? exit_sig = 1;
}
// 傳輸圖像
struct lws* g_wsi = NULL;
long g_wsi_port = 9000;
char* g_wsi_protocolname = "hello";?
MyThread * g_pThread = NULL;
/**
?* 會話上下文對象,結構根據需要自定義
?*/
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_FILTER_PROTOCOL_CONNECTION: //這里的wsi中才有url內容
?? ??? ?// 客戶端連上來看看是否最新token
?? ??? ?{?? ??? ?
?? ??? ??? ?char content_length_str[200] = {0};
?? ??? ??? ?lws_hdr_copy(wsi,content_length_str,200,(lws_token_indexes)0);
?? ??? ??? ?char chartoken[200] = {0};
?? ??? ??? ?g_pThread->GetNewToken(chartoken);?
?? ??? ??? ?if (chartoken[0]=='\0') // 沒有最新的token
?? ??? ??? ?{
?? ??? ??? ??? ?return -1;
?? ??? ??? ?}
?? ??? ??? ?else
?? ??? ??? ?{
?? ??? ??? ??? ?if(strstr(content_length_str,chartoken) != NULL)
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?map_wsi_token.insert(pair<long,string>(long(wsi),string(content_length_str)));
?? ??? ??? ??? ??? ?g_wsi = ?wsi;?? ?
?? ??? ??? ??? ??? ?OutputDebugStringA("PROTOCOL_CONNECTION \r\n");
?? ??? ??? ??? ?}
?? ??? ??? ??? ?else
?? ??? ??? ??? ??? ?return -1;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?break;
? ? case LWS_CALLBACK_ESTABLISHED: ? ? ? // 當服務器和客戶端完成握手后
? ? ??? ?OutputDebugStringA("LWS_CALLBACK_ESTABLISHED \r\n");
? ? ? ? break;
? ? case LWS_CALLBACK_RECEIVE: // 當接收到客戶端發來的幀,首先驗證token是否有效
?? ??? ??? ?{
?? ??? ??? ??? ?map<long,string>::iterator iter = map_wsi_token.find(long(wsi));
?? ??? ??? ??? ?if(iter != map_wsi_token.end())
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?char chartoken[200] = {0};
?? ??? ??? ??? ??? ?g_pThread->GetNewToken(chartoken);
?? ??? ??? ??? ??? ?string strtoken = iter->second;
?? ??? ??? ??? ??? ?if(strtoken.find(chartoken) == -1)
?? ??? ??? ??? ??? ?{
?? ??? ??? ??? ??? ??? ?return -1;
?? ??? ??? ??? ??? ?}
?? ??? ??? ??? ?}
?? ??? ??? ??? ?else
?? ??? ??? ??? ?{
?? ??? ??? ??? ??? ?return -1;
?? ??? ??? ??? ?}
?? ??? ??? ?}
? ? ? ? break;
? ? case LWS_CALLBACK_SERVER_WRITEABLE: ? // 當此連接可寫時
?? ??? ?OutputDebugStringA("write WaitForSingleObject ?g_hFullBufferSemaphore\r\n");
?? ??? ?WaitForSingleObject(g_pThread->g_hFullBufferSemaphore, INFINITE); // 等待是否已經生產了產品
?? ??? ?if(g_pThread->_outputbuf != NULL)
?? ??? ?{
?? ??? ??? ?// 前面LWS_PRE個字節必須留給LWS?? ?
?? ??? ??? ?int isz = g_pThread->_outsize;//sizeof(g_pThread->_outputbuf);
?? ??? ??? ?memset(data->buf+ LWS_PRE, 0, isz);
?? ??? ??? ?memcpy(data->buf+ LWS_PRE, g_pThread->_outputbuf, isz);
?? ??? ??? ?data->len = isz;
?? ??? ??? ?lws_write(wsi, data->buf+LWS_PRE, isz, (lws_write_protocol)g_pThread->_datatype);
?? ??? ??
?? ??? ??? ?// 下面的調用允許在此連接上接收數據;
?? ??? ??? ?lws_rx_flow_control(wsi, 1);
?? ??? ??? ?g_pThread->_outsize = 0;
?? ??? ?}
?? ??? ?ReleaseSemaphore(g_pThread->g_hEmptyBufferSemaphore, 1, NULL); // 我消費完了,通知生產者
? ? ? ? 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);
?? ??? ??? ??? ?g_wsi = NULL;
?? ??? ??? ?}
?? ??? ?}
?? ??? ?break;
? ? }
? ? // 回調函數最終要返回0,否則無法創建服務器
? ? return 0;
}
struct lws_protocols protocols[] = {
? ? {
? ? ? ? //協議名稱,協議回調,接收緩沖區大小 ,有效負載限制
? ? ? ? g_wsi_protocolname, protocol_my_callback, sizeof(struct session_data), MAX_PAYLOAD_SIZE,?
? ? },
? ? {
? ? ? ? NULL, NULL, ? 0 // 最后一個元素固定為此格式
? ? }
};
MyThread::MyThread(void)
{?? ?
?? ?irun = true;
?? ?memset(newtoken,0,128);?
?? ?_outputbuf= NULL;
?? ?_datatype = 0;
}
MyThread::~MyThread(void)
{
?? ?StartThread(false);
?? ?CloseHandle(g_hEmptyBufferSemaphore);
?? ?CloseHandle(g_hFullBufferSemaphore);
?? ?if(_outputbuf != NULL)
?? ?{?? ?
?? ??? ?free (_outputbuf);
?? ??? ?_outputbuf = NULL;
?? ?}
}
void MyThread::Run()
{?? ?
?? ? ?// 信號處理函數
? ? signal(SIGTERM, sighdl);
? ? struct lws_context_creation_info ctx_info = { 0 };
? ? ctx_info.port = g_wsi_port;
? ? ctx_info.iface = NULL; // 在所有網絡接口上監聽
? ? ctx_info.protocols = protocols;
? ? ctx_info.gid = -1;
? ? ctx_info.uid = -1;
? ? ctx_info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
? ? struct lws_context* context = lws_create_context(&ctx_info);
? ? while (!exit_sig) {
? ? ? ? lws_service(context, 50);
?? ??? ?if(g_wsi != NULL)
?? ??? ??? ?lws_callback_on_writable(g_wsi);
?? ??? ?OutputDebugStringA("lws_service 100\r\n");
? ? }
?? ??? ??? ?
?? ?OutputDebugStringA("lws_service exit_sig\r\n");
? ? lws_context_destroy(context);
}
int MyThread::SendData(unsigned char *outbuffer,int size,int datatype)
{
?? ?OutputDebugStringA("WaitForSingleObject g_hEmptyBufferSemaphore ?\r\n");
?? ?// 等待消費線程,之后等來時計數-1, 初始該信號為1,
?? ?WaitForSingleObject(g_hEmptyBufferSemaphore, INFINITE);?
?? ?if(isznote <size)
?? ?{
?? ??? ?isznote = size;
?? ??? ?_outputbuf = (unsigned char*)realloc(_outputbuf,isznote*sizeof(unsigned char));
?? ??? ?memset(_outputbuf,0,isznote*sizeof(unsigned char));
?? ??? ?char info[100] = {0};
?? ??? ?sprintf(info,"**sz:%d \r\n",isznote*sizeof(unsigned char));
?? ??? ?OutputDebugStringA(info);
?? ?}
?? ?_datatype = datatype;
?? ?memcpy(_outputbuf,outbuffer,size*sizeof(unsigned char));
?? ?_outsize = size;
?? ?if(g_wsi != NULL)
?? ??? ?lws_callback_on_writable(g_wsi);?? ?//需要給客戶端應答時,觸發一次寫回調
?? ?
?? ?ReleaseSemaphore(g_hFullBufferSemaphore, 1, NULL); //通知消費線程,信號+1,
?? ?
?? ?OutputDebugStringA("ReleaseSemaphore g_hFullBufferSemaphore ?\r\n");
?? ?return 0;
}
void MyThread::GetNewToken(char* info)
{
?? ?strcpy(info,newtoken);
}
void MyThread::SetNewToken(const char* info)
{
?? ?memset(newtoken,0,128);?
?? ?strcpy(newtoken,info);
}
int MyThread::ThreadInit(long port,const char* protocolname)
{
?? ?g_event = CreateEvent(NULL, false, false, NULL); //創建一個匿名事件,當參數bManualReset設置為false時
?? ?g_pThread = this;
?? ?g_wsi_protocolname = (char*)protocolname;
?? ?protocols[0].name = g_wsi_protocolname;
?? ?g_wsi_port = port;
?? ?if(_outputbuf == NULL)
?? ?{
?? ??? ?isznote = 4096;
?? ??? ?_outputbuf = (unsigned char*)malloc(isznote*sizeof(unsigned char*));
?? ?}
?? ?g_hEmptyBufferSemaphore = CreateSemaphore( NULL, 1, 1, NULL); //創建信號量1
?? ?g_hFullBufferSemaphore = CreateSemaphore( NULL, 0, 1, NULL); //
?? ?return 0;
}
void MyThread::StartThread(bool brun)
{
?? ?if(brun)
?? ?{
?? ? ? ?thread=new CThreadHandler(this);//線程類
?? ??? ?thread->Start();//啟動線程
?? ?}
?? ?else
?? ?{
?? ??? ?exit_sig = 0;// 設置退出信號
?? ??? ?int code = thread->Join(5000);
?? ??? ?if(code == STILL_ACTIVE)
?? ??? ?{
?? ??? ??? ?bool bstop = thread->Terminate(code);
?? ??? ??? ?if(bstop== false)
?? ??? ??? ?{
?? ??? ??? ??? ?printf("thread is not terminate \r\n");
?? ??? ??? ?}
?? ??? ?}
?? ??? ?else
?? ??? ?{
?? ??? ??? ?printf("thread is not STILL_ACTIVE \r\n");
?? ??? ?}
?? ?}
}
總結
以上是生活随笔為你收集整理的c++ libwebsocket库应用开发2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python Basic - Pytho
- 下一篇: VisualStudio2022 Ent