Linux下编译 libwebsockets简介和使用示例

news/2024/12/27 10:35:18 标签: linux, websocket, 音视频

目录

1:简单介绍:

2:项目地址

3:编译

3.1:集成介绍

3.2:编译

4:客户端服务端示例:

4.1 客户端示例

4.2 服务端示例:


1:简单介绍:

    Linux下编译libwebsockets和使用简单示例,给需要的各位参考

          libwebsockets是一个小巧强大的库,它使用 C 语言编写,可以帮助开发者轻松实现 WebSocket 协议。WebSocket 是一种网络通信协议,它允许服务器和客户端之间建立一个持久的连接,这样双方就可以实时地发送和接收消息了。

优点

  1. 轻量级和高效:libwebsockets 设计为轻量级,适合嵌入式系统和资源受限的环境,能够高效地处理 WebSocket 和 HTTP 请求。
  2. 双向通信:支持全双工通信,允许服务器主动推送数据到客户端,减少了延迟。
  3. 较少的通信开销:相比于传统的 HTTP 协议,WebSocket 的通信开销较小,因为它在建立连接后可以持续使用同一连接进行数据交换。
  4. 多协议支持:除了 WebSocket,libwebsockets 还支持 HTTP/1、HTTP/2、MQTT 等多种协议,具有良好的扩展性。
  5. 安全性:内建对 SSL/TLS 的支持,能够实现安全的通信

缺点

  1. 复杂性:libwebsockets 的接口较底层,许多逻辑需要开发者自行封装实现,这可能增加开发的复杂性。
  2. 线程安全性:该库不是线程安全的,因此在多线程环境中使用时需要特别注意线程和锁的管理。
  3. 兼容性问题:虽然大多数现代浏览器支持 WebSocket,但在一些旧版浏览器中可能存在兼容性问题。
  4. 重连机制:WebSocket 需要处理网络不稳定时的重连问题,这在某些情况下可能会导致实现上的复杂性。

2:项目地址

这里有几个不同的地址,防止有些网络问题获取不到

github地址:

warmcat/libwebsockets: canonical libwebsockets.org networking libraryicon-default.png?t=O83Ahttps://github.com/warmcat/libwebsocketsgitcode地址:GitCode - 全球开发者的开源社区,开源代码托管平台icon-default.png?t=O83Ahttps://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.icon-default.png?t=O83Ahttps://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 Exampleicon-default.png?t=O83Ahttps://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;
}

后续会继续补充,使用上遇到的问题和解决方式


http://www.niftyadmin.cn/n/5801618.html

相关文章

在HTML中使用Vue如何使用嵌套循环把集合中的对象集合中的对象元素取出来(我的意思是集合中还有一个集合那种)

在 Vue.js 中处理嵌套集合&#xff08;即集合中的对象包含另一个集合&#xff09;时&#xff0c;使用多重 v-for 指令来遍历这些层次结构。每个 v-for 指令可以用于迭代一个特定级别的数据集&#xff0c;并且可以在模板中嵌套多个 v-for 来访问更深层次的数据。 例如&#xff…

V-Ray 来到 Blender:为艺术家提供专业级渲染

Chaos 正式宣布将其行业领先的渲染引擎 V-Ray 集成到 Blender 中。这一备受期待的开发为 Blender 用户带来了专业级渲染功能&#xff0c;使他们能够直接在他们最喜欢的 3D 平台中制作令人惊叹的、逼真的图像和动画。 渲染 强大的可缩放渲染 使用 V-Ray 将您的渲染提升到一个…

数据库-mysql高阶语句

mysql高阶语句 mysql高阶语句对复杂条件的查询 1、使用select语句时&#xff0c;如何按照顺序对结果进行排序 select name from info order by score desc; #我们查询的是name&#xff0c;按照成绩实现升序的操作select id,name from info order by score desc; #从大到小…

Springboot3国际化

国际化实现步骤 Spring Boot 3 提供了强大的国际化支持&#xff0c;使得应用程序可以根据用户的语言和区域偏好适配不同的语言和地区需求。 添加国际化资源文件&#xff1a; 国际化资源文件通常放在 src/main/resources 目录下&#xff0c;并按照不同的语言和地区命名&#xf…

微机接口课设——基于Proteus和8086的打地鼠设计(8255、8253、8259)

原理图设计 汇编代码 ; I/O 端口地址定义 IOY0 EQU 0600H IOY1 EQU 0640H IOY2 EQU 0680HMY8255_A EQU IOY000H*2 ; 8255 A 口端口地址 MY8255_B EQU IOY001H*2 ; 8255 B 口端口地址 MY8255_C EQU IOY002H*2 ; 8255 C 口端口地址 MY8255_MODE EQU IOY003H*2 ; …

RTOS 基础知识

**实时操作系统&#xff08;RTOS, Real-Time Operating System&#xff09;**是一种专为实时性要求设计的操作系统&#xff0c;具有确定性和高效性。RTOS 的系统架构围绕任务调度、时间管理和资源管理展开&#xff0c;以确保系统能够在规定时间内响应外部事件。以下是RTOS的系统…

绝美的数据处理图-三坐标轴-散点图-堆叠图-数据可视化图

clc clear close all %% 读取数据 load(MyColor.mat) %读取颜色包for iloop 1:25 %提取工作表数据data0(iloop) {readtable(data.xlsx,sheet,iloop)}; end%% 解析数据 countzeros(23,14); for iloop 1:25index(iloop) { cell2mat(table2array(data0{1,iloop}(1,1)))};data(i…

Java获取自身被调用点

1. 场景 打印日志的时候&#xff0c;需要获取是在哪个地方被调用了&#xff0c;把调用点的信息一并打印出来。 2. 获取自身被调用点的方法 可以通过获取线程的调用栈&#xff0c;遍历后找到调用点。 3. 代码实现 import java.text.SimpleDateFormat; import java.util.Dat…