目录
1:简单介绍:
2:项目地址
3:编译
3.1:集成介绍
3.2:编译
4:客户端服务端示例:
4.1 客户端示例
4.2 服务端示例:
1:简单介绍:
Linux下编译libwebsockets和使用简单示例,给需要的各位参考
libwebsockets
是一个小巧强大的库,它使用 C 语言编写,可以帮助开发者轻松实现 WebSocket 协议。WebSocket 是一种网络通信协议,它允许服务器和客户端之间建立一个持久的连接,这样双方就可以实时地发送和接收消息了。
优点
- 轻量级和高效:libwebsockets 设计为轻量级,适合嵌入式系统和资源受限的环境,能够高效地处理 WebSocket 和 HTTP 请求。
- 双向通信:支持全双工通信,允许服务器主动推送数据到客户端,减少了延迟。
- 较少的通信开销:相比于传统的 HTTP 协议,WebSocket 的通信开销较小,因为它在建立连接后可以持续使用同一连接进行数据交换。
- 多协议支持:除了 WebSocket,libwebsockets 还支持 HTTP/1、HTTP/2、MQTT 等多种协议,具有良好的扩展性。
- 安全性:内建对 SSL/TLS 的支持,能够实现安全的通信
缺点
- 复杂性:libwebsockets 的接口较底层,许多逻辑需要开发者自行封装实现,这可能增加开发的复杂性。
- 线程安全性:该库不是线程安全的,因此在多线程环境中使用时需要特别注意线程和锁的管理。
- 兼容性问题:虽然大多数现代浏览器支持 WebSocket,但在一些旧版浏览器中可能存在兼容性问题。
- 重连机制:WebSocket 需要处理网络不稳定时的重连问题,这在某些情况下可能会导致实现上的复杂性。
2:项目地址
这里有几个不同的地址,防止有些网络问题获取不到
github地址:
warmcat/libwebsockets: canonical libwebsockets.org networking libraryhttps://github.com/warmcat/libwebsocketsgitcode地址:GitCode - 全球开发者的开源社区,开源代码托管平台https://gitcode.com/gh_mirrors/li/libwebsockets/overview?utm_source=csdn_blog_hover&isLogin=1
示例项目地址:
GitHub - iamscottmoyers/simple-libwebsockets-example: Simple libwebsockets ExampleSimple libwebsockets Example. Contribute to iamscottmoyers/simple-libwebsockets-example development by creating an account on GitHub.https://github.com/iamscottmoyers/simple-libwebsockets-example/blob/master
3:编译
3.1:集成介绍
在 libwebsockets 的顶层 CMakeLists.txt 文件中,看到许多选项来启用或禁用不同的功能、示例和应用程序。以下是一些关键的部分根据需要启用或禁用它们来减少编译时间:
功能选项
LWS_WITH_STATIC 编译静态库
LWS_WITH_SHARED 编译动态库
LWS_WITH_DISTRO_RECOMMENDED: 启用推荐的功能集,适用于发行版包装。
LWS_WITH_SSL: 启用 SSL 支持。
LWS_WITH_HTTP2: 启用 HTTP/2 支持。
LWS_WITH_ZLIB: 启用 zlib 支持。
LWS_WITH_LIBEVENT: 启用 libevent 支持。
LWS_WITH_PLUGINS: 启用插件支持。
客户端/服务器/测试应用程序
LWS_WITHOUT_CLIENT: 不构建客户端部分。
LWS_WITHOUT_SERVER: 不构建服务器部分。
LWS_WITHOUT_TESTAPPS: 不构建测试应用程序。
LWS_WITHOUT_TEST_SERVER: 不构建测试服务器。
LWS_WITHOUT_TEST_PING: 不构建 ping 测试应用程序。
LWS_WITHOUT_TEST_CLIENT: 不构建客户端测试应用程序。
示例
LWS_WITH_MINIMAL_EXAMPLES: 构建最小化的示例。
LWS_WITH_LWSWS: 构建 libwebsockets Web 服务器示例。
特定平台
LWS_WITH_ESP32: 为 ESP32 构建。
LWS_PLAT_OPTEE: 为 OPTEE 构建。
LWS_PLAT_FREERTOS: 为 FreeRTOS 构建。
LWS_PLAT_ANDROID: Android 平台。
LWS_PLAT_BAREMETAL: 为裸机构建。
其他
LWS_WITH_SELFTESTS: 启用自测试。
LWS_WITH_EXPORT_LWSTARGETS: 导出 CMake 目标。
3.2:编译
1.创建build 存放编译文件,libwebsockets没有makeclean,重新编译时,清空build就行
2.创建out 存放生成的库文件
3.注意你的DCMAKE_CXX_COMPILER和DCMAKE_CXX_COMPILER必须是需要使用绝对路径
4.关闭ssl、libevent相关,关闭示例编译,如果你需要libevent或者ssl相关,你需要先编译这些依赖后再编译libwebsocket
5.设置编译系统为linux
6.生成动态和静态库两种类型
# mkdir build
# mkdir out
# cmake ../ -DCMAKE_C_COMPILER=/你的全路径xxx/xx-linux-gcc \
-DCMAKE_CXX_COMPILER=/你的全路径xxx/xx-linux-g++ \
-DLWS_WITH_STATIC=ON \
-DLWS_WITH_SHARED=ON \
-DCMAKE_INSTALL_PREFIX=/你的路径xxx/output \
-DLWS_WITH_MINIMAL_EXAMPLES=OFF \
-DLWS_STATIC_PIC=ON \
-DLWS_WITHOUT_TESTAPPS=ON \
-DCMAKE_SYSTEM_NAME=Linux \
-DLWS_WITH_SSL=OFF
# make
# make install
cmake其他参数 :
-DCMAKE_SYSTEM_NAME 指定系统为Linux
-DCMAKE_C_COMPILER 需要使用绝对路径
-DCMAKE_CXX_COMPILER c++编译器
-DLWS_OPENSSL_INCLUDE_DIRS Openssl头文件目录位置
-DLWS_OPENSSL_LIBRARIES Openssl动态库位置
-DLIBEVENT_INCLUDE_DIRS libevent头文件目录位置
-DLIBEVENT_LIBRARIES libevent动态链接库位置
编译后 会在out路径下生成对应的bin、lib、include
4:客户端服务端示例:
示例是github上的开源示例,可能有些朋友会因为网络问题 看不到,我这里粘贴出来,给各位参考,项目地址为:
iamscottmoyers/simple-libwebsockets-example: Simple libwebsockets Examplehttps://github.com/iamscottmoyers/simple-libwebsockets-example/tree/master
4.1 客户端示例
#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static struct lws *web_socket = NULL;
#define EXAMPLE_TX_BUFFER_BYTES 10
static int callback_example( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_CLIENT_ESTABLISHED:
lws_callback_on_writable( wsi );
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
/* Handle incomming messages here. */
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
{
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + EXAMPLE_TX_BUFFER_BYTES + LWS_SEND_BUFFER_POST_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
size_t n = sprintf( (char *)p, "%u", rand() );
lws_write( wsi, p, n, LWS_WRITE_TEXT );
break;
}
case LWS_CALLBACK_CLIENT_CLOSED:
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
web_socket = NULL;
break;
default:
break;
}
return 0;
}
enum protocols
{
PROTOCOL_EXAMPLE = 0,
PROTOCOL_COUNT
};
static struct lws_protocols protocols[] =
{
{
.name = "example-protocol", /* Protocol name*/
.callback = callback_example, /* Protocol callback */
.per_session_data_size = 0, /* Protocol callback 'userdata' size */
.rx_buffer_size = 0, /* Receve buffer size (0 = no restriction) */
.id = 0, /* Protocol Id (version) (optional) */
.user = NULL, /* 'User data' ptr, to access in 'protocol callback */
.tx_packet_size = 0 /* Transmission buffer size restriction (0 = no restriction) */
},
LWS_PROTOCOL_LIST_TERM /* terminator */
};
int main( int argc, char *argv[] )
{
struct lws_context_creation_info info;
memset( &info, 0, sizeof(info) );
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
struct lws_context *context = lws_create_context( &info );
time_t old = 0;
while( 1 )
{
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;
memset(&ccinfo, 0, sizeof(ccinfo));
ccinfo.context = context;
ccinfo.address = "localhost";
ccinfo.port = 8000;
ccinfo.path = "/";
ccinfo.host = lws_canonical_hostname( context );
ccinfo.origin = "origin";
ccinfo.protocol = protocols[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 ); /* NOTE: since v3.2, timeout_ms may be set to '0', since it internally ignored */
}
lws_context_destroy( context );
return 0;
}
4.2 服务端示例:
#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
static struct lws *web_socket = NULL;
#define EXAMPLE_TX_BUFFER_BYTES 10
static int callback_example( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{
switch( reason )
{
case LWS_CALLBACK_CLIENT_ESTABLISHED:
lws_callback_on_writable( wsi );
break;
case LWS_CALLBACK_CLIENT_RECEIVE:
/* Handle incomming messages here. */
break;
case LWS_CALLBACK_CLIENT_WRITEABLE:
{
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + EXAMPLE_TX_BUFFER_BYTES + LWS_SEND_BUFFER_POST_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
size_t n = sprintf( (char *)p, "%u", rand() );
lws_write( wsi, p, n, LWS_WRITE_TEXT );
break;
}
case LWS_CALLBACK_CLIENT_CLOSED:
case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:
web_socket = NULL;
break;
default:
break;
}
return 0;
}
enum protocols
{
PROTOCOL_EXAMPLE = 0,
PROTOCOL_COUNT
};
static struct lws_protocols protocols[] =
{
{
.name = "example-protocol", /* Protocol name*/
.callback = callback_example, /* Protocol callback */
.per_session_data_size = 0, /* Protocol callback 'userdata' size */
.rx_buffer_size = 0, /* Receve buffer size (0 = no restriction) */
.id = 0, /* Protocol Id (version) (optional) */
.user = NULL, /* 'User data' ptr, to access in 'protocol callback */
.tx_packet_size = 0 /* Transmission buffer size restriction (0 = no restriction) */
},
LWS_PROTOCOL_LIST_TERM /* terminator */
};
int main( int argc, char *argv[] )
{
struct lws_context_creation_info info;
memset( &info, 0, sizeof(info) );
info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */
info.protocols = protocols;
info.gid = -1;
info.uid = -1;
struct lws_context *context = lws_create_context( &info );
time_t old = 0;
while( 1 )
{
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;
memset(&ccinfo, 0, sizeof(ccinfo));
ccinfo.context = context;
ccinfo.address = "localhost";
ccinfo.port = 8000;
ccinfo.path = "/";
ccinfo.host = lws_canonical_hostname( context );
ccinfo.origin = "origin";
ccinfo.protocol = protocols[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 ); /* NOTE: since v3.2, timeout_ms may be set to '0', since it internally ignored */
}
lws_context_destroy( context );
return 0;
}
后续会继续补充,使用上遇到的问题和解决方式