当前位置:网站首页>The simplest and complete example of libwebsockets
The simplest and complete example of libwebsockets
2022-04-23 07:23:00 【dotphoenix】
/*
* simplest_websocket_example - The simplest and most complete use libwebsocket Example
*
* Copyright (C) 2020 Zhu Nengjie <[email protected]>
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include <libwebsockets.h>
#include <glib.h>
#include <string.h>
#include <stdio.h>
// The main function of this example is :
//1. ws The client will periodically report to ws The server updates a number , The number is incremented , see :LWS_CALLBACK_CLIENT_WRITEABLE;
//2. ws After the server receives the number , see :LWS_CALLBACK_RECEIVE, It will be preserved ;
//3. When server When you can write , This number will be sent to all clients ( Including clients that send numbers ), see :LWS_CALLBACK_SERVER_WRITEABLE
//4. When the client receives the number , It will show , see :LWS_CALLBACK_CLIENT_RECEIVE
//5. Browser access http://localhost:8000, ws The server ( Because it is also a standard http The server ) Will return an automatically created html file ,
// The html The content of the document is html_contenti The contents of variables , Its main function is through js Build a ws client , And connect to localhost:8000 This
// ws The server , And when the data is received , Update to page . When someone asks localhost:8000 Request to send http When asked , Return the file , see :LWS_CALLBACK_RECEIVE
// compile : Must be installed first libwebsocket and glib-2.0, ssl It shouldn't be necessary , But if not, it may fail to compile , Pay attention to revise ssl The path is the path of your own computer
//gcc -g -Wall simplest_websocket_example.c -o simplest_websocket_example `pkg-config --libs --cflags glib-2.0 libwebsockets` -I/usr/local/Cellar/[email protected]/1.1.1d/include
// This content will be automatically written to a html In the document , His function is to use js Create a websocket client , When you get the data , Refresh the page
const char *html_content = " <!DOCTYPE html>"
"<html> \n"
"<title>Websocket example</title>\n"
"<script>\n"
" var socket = new WebSocket( \"ws://\" + document.domain + ':' + location.port, \"ws-protocol-example\" );\n"
" function update(msg) { document.getElementById(\"num\").innerHTML = msg; }\n"
" socket.onopen = function() { console.log(\"socket open\"); update(\"open\"); }\n"
" socket.onclose = function() { console.log(\"socket close\"); update(\"closed\"); }\n"
" socket.onmessage = function(msg) { console.log(\"socket message: \" + msg.data); update(msg.data); }\n"
"</script>\n"
"<body>\n"
"<p id=\"num\"></p>\n"
"</body>\n"
"</html>\n";
// establish html Path to file
static char example_html_file_path[512] = {0};
// return html Path to file , Will automatically get the current running path
static const char* get_html_file_path()
{
if(strlen(example_html_file_path) == 0)
{
getcwd(example_html_file_path, 512);
strcat(example_html_file_path, "/websocket_example.html");
}
return (const char*)example_html_file_path;
}
// Write content to html In the document , Every time you open a page here, it will be recreated , Consider making a judgment , Don't create... Every time
static void create_html_file()
{
FILE *f;
const char* pathname = get_html_file_path();
if ((f = fopen(pathname, "w+")) == NULL)
{
printf("open file error");
return ;
}
fwrite(html_content, 1, strlen(html_content), f);
fflush(f);
fclose(f);
}
//html Protocol callback function
static int callback_http( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_HTTP:
create_html_file();
printf("%s->%s\n", "LWS_CALLBACK_HTTP", get_html_file_path());
lws_serve_http_file( wsi, get_html_file_path(), "text/html", NULL, 0 );
break;
default:
break;
}
return 0;
}
#define EXAMPLE_RX_BUFFER_BYTES (10)
// A definition of payload structure , Used to store ws Data sent and received
struct payload
{
unsigned char data[LWS_SEND_BUFFER_PRE_PADDING + EXAMPLE_RX_BUFFER_BYTES + LWS_SEND_BUFFER_POST_PADDING];
size_t len;
} ;
struct payload server_received_payload;
//ws Server side ws(ws-protocol-example) Protocol callback function
static int callback_example_server( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_RECEIVE: // Receive the data
memset(&server_received_payload.data[LWS_SEND_BUFFER_PRE_PADDING], 0, len + 1);
memcpy( &server_received_payload.data[LWS_SEND_BUFFER_PRE_PADDING], in, len );
server_received_payload.len = len;
printf("\033[31mserver callback: %s->%s\n", "LWS_CALLBACK_RECEIVE", &server_received_payload.data[LWS_SEND_BUFFER_PRE_PADDING]);
lws_callback_on_writable_all_protocol( lws_get_context( wsi ), lws_get_protocol( wsi ) );
break;
case LWS_CALLBACK_SERVER_WRITEABLE: // Can write // Will write data to all connections , This is at least 2 A connection ( Send digital ws Client and html Built inside ws client ), therefore log You can see 2 strip
printf("\033[31mserver callback: %s->%s\n", "LWS_CALLBACK_SERVER_WRITEABLE", &server_received_payload.data[LWS_SEND_BUFFER_PRE_PADDING]);
lws_write( wsi, &server_received_payload.data[LWS_SEND_BUFFER_PRE_PADDING], server_received_payload.len, LWS_WRITE_TEXT );
break;
default:
break;
}
return 0;
}
//ws The server supports... On the same port 2 Kind of agreement ,http and ws( The concrete is ws-protocol-example, In fact, there can be a few more ws agreement )
static struct lws_protocols server_protocols[] =
{
/* The first protocol must always be the HTTP handler */
{
"http-only", /* name */
callback_http, /* callback */
0, /* No per session data. */
0, /* max frame size / rx buffer */
},
{
"ws-protocol-example",
callback_example_server,
0,
EXAMPLE_RX_BUFFER_BYTES,
},
{ NULL, NULL, 0, 0 } /* terminator */
};
//s Stop server
static int stop_server = 0;
int main_server()
{
struct lws_context_creation_info info;
memset( &info, 0, sizeof(info) );
info.port = 8000;// Listening port
info.protocols = server_protocols; // Which protocols are supported
info.gid = -1;
info.uid = -1;
struct lws_context *context = lws_create_context( &info );
printf("websockets server starts at %d \n", info.port);
while( stop_server == 0 )
{
lws_service( context, /* timeout_ms = */ 1000000 );
}
lws_context_destroy( context );
return 0;
}
///
The following is a ws The content of the client /
///
// Used to save the connection between the client and the server
static struct lws *web_socket = NULL;
struct payload client_received_payload; // Save the data received by the client
static int report_count = 0; // Data sent by the client
// Client callback
static int callback_example_client( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_CLIENT_ESTABLISHED: // Connection established successfully
printf("\033[34mclient callback: %s->%s\n", "LWS_CALLBACK_CLIENT_ESTABLISHED", "");
lws_callback_on_writable( wsi );
break;
case LWS_CALLBACK_CLIENT_RECEIVE:// Echo the data sent back by the server
memset(&client_received_payload.data[LWS_SEND_BUFFER_PRE_PADDING], 0, len + 1);
memcpy( &client_received_payload.data[LWS_SEND_BUFFER_PRE_PADDING], in, len );
client_received_payload.len = len;
printf("\033[34mclient callback: %s->%s\n", "LWS_CALLBACK_CLIENT_RECEIVE", &client_received_payload.data[LWS_SEND_BUFFER_PRE_PADDING]);
break;
case LWS_CALLBACK_CLIENT_WRITEABLE: // Every callback ,count Add one , Send to the server
{
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + EXAMPLE_RX_BUFFER_BYTES + LWS_SEND_BUFFER_POST_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
size_t n = sprintf( (char *)p, "%u", report_count++ );
printf("\033[34mclient callback: %s->%s\n", "LWS_CALLBACK_CLIENT_WRITEABLE", p);
lws_write( wsi, p, n, LWS_WRITE_TEXT );
break;
}
case LWS_CALLBACK_CLOSED:
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
// Connection failure or interruption , empty , Easy to reconnect
web_socket = NULL;
break;
default:
break;
}
return 0;
}
// The client only needs to support ws(ws-protocol-example)
enum client_protocols_type
{
WS_PROTOCOL_EXAMPLE = 0,
PROTOCOL_COUNT
};
static struct lws_protocols client_protocols[] =
{
{
"ws-protocol-example", // Name of agreement , One port can establish multiple ports ws agreement
callback_example_client,
0,
EXAMPLE_RX_BUFFER_BYTES,
},
{ NULL, NULL, 0, 0 } /* terminator */
};
static int stop_client = 0;
int main_client()
{
struct lws_context_creation_info info;
memset( &info, 0, sizeof(info) );
info.port = CONTEXT_PORT_NO_LISTEN;
info.protocols = client_protocols;
info.gid = -1;
info.uid = -1;
struct lws_context *context = lws_create_context( &info );
time_t old = 0;
while( stop_client == 0 )
{
struct timeval tv;
gettimeofday( &tv, NULL );
/* Connect if we are not connected to the server. */
if( !web_socket && tv.tv_sec != old )
{
struct lws_client_connect_info ccinfo = {0};
ccinfo.context = context;
ccinfo.address = "localhost";
ccinfo.port = 8000;
ccinfo.path = "/";
ccinfo.host = lws_canonical_hostname( context );
ccinfo.origin = "origin";
ccinfo.protocol = client_protocols[WS_PROTOCOL_EXAMPLE].name;
web_socket = lws_client_connect_via_info(&ccinfo);
}
if( tv.tv_sec != old )
{
/* Send a random number to the server every second. */
lws_callback_on_writable( web_socket );
old = tv.tv_sec;
}
lws_service( context, /* timeout_ms = */ 250 );// stay V3.2 after ,timeout The value of has been discarded , The bottom layer schedules itself ; So how to control the frequency in this place , Unclear
}
lws_context_destroy( context );
return 0;
}
// function server The thread function of
void thread_func_server(void *p)
{
main_server();
}
int main( int argc, char *argv[] )
{
//server stay work thread It calls , The client runs on main thread
GThread* server_thread = g_thread_new("server_thread", (GThreadFunc)(thread_func_server), NULL);
main_client();
g_thread_join(server_thread); // wait for , Infinite loop
}
版权声明
本文为[dotphoenix]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/04/202204230609059195.html
边栏推荐
- 【點雲系列】SG-GAN: Adversarial Self-Attention GCN for Point Cloud Topological Parts Generation
- Keras如何保存、加载Keras模型
- 被 onnx.checker.check_model 检查出的常见错误
- [point cloud series] pnp-3d: a plug and play for 3D point clouds
- [dynamic programming] different binary search trees
- . net encountered failed to decode downloaded font while loading font:
- 【动态规划】杨辉三角
- 1.1 pytorch and neural network
- PyTorch 10. 学习率
- 第3章 Pytorch神经网络工具箱
猜你喜欢
Write a wechat double open gadget to your girlfriend
SSL/TLS应用示例
【点云系列】 A Rotation-Invariant Framework for Deep Point Cloud Analysis
face_recognition人脸检测
Face_ Recognition face detection
Chapter 5 fundamentals of machine learning
【期刊会议系列】IEEE系列模板下载指南
第1章 NumPy基础
微信小程序 使用wxml2canvas插件生成图片部分问题记录
第3章 Pytorch神经网络工具箱
随机推荐
ArcGIS License Server Administrator 无法启动解决方法
Handlerthread principle and practical application
多机多卡训练时的错误
F.pad 的妙用
Raspberry Pie: two color LED lamp experiment
Gee configuring local development environment
第1章 NumPy基础
PyTorch最佳实践和代码编写风格指南
【动态规划】杨辉三角
【点云系列】Fully-Convolutional geometric features
Chapter 4 pytoch data processing toolbox
rearrange 和 einsum 真的优雅吗
Pytorch model pruning example tutorial III. multi parameter and global pruning
PyTorch 19. PyTorch中相似操作的区别与联系
PyTorch 10. 学习率
【点云系列】FoldingNet:Point Cloud Auto encoder via Deep Grid Deformation
Five methods are used to obtain the parameters and calculation of torch network model
Compression and acceleration technology of deep learning model (I): parameter pruning
Pymysql connection database
MySQL数据库安装与配置详解