【C++】libwebsockets库的简易教程(附源码)

2023-10-14 20:10

本文主要是介绍【C++】libwebsockets库的简易教程(附源码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1、常用的一些api

2、服务器

3、客户端

4、踩到的一些坑


1、常用的一些api

(1)lws_create_context:创建上下文对面,管理ws

        lws_create_context是libwebsockets库中的函数,用于创建一个WebSocket上下文。WebSocket上下文是一个结构体,包含了与WebSocket相关的所有信息和状态。在创建WebSocket连接之前,需要先创建一个WebSocket上下文。lws_create_context函数的作用是初始化WebSocket上下文,并返回一个指向WebSocket上下文的指针。

(2)lws_context_destroy:销毁上下文对象

        lws_context_destroy 是一个函数,用于销毁一个 libwebsockets 应用程序的上下文。它会释放分配给上下文的所有资源,包括套接字、线程、缓冲区等。调用此函数后,应用程序将无法再使用上下文,因此应该确保在不需要上下文时才调用此函数。

(3)lws_client_connect_via_info:连接到WebSocket服务器

        lws_client_connect_via_info是libwebsockets库中的一个函数,它的作用是通过提供的连接信息来建立一个客户端连接。这个函数可以用于在客户端应用程序中连接到服务器。 

具体来说,lws_client_connect_via_info函数需要提供以下信息:

1. 连接协议的名称,例如http、https、websocket等。

2. 服务器的主机名或IP地址。

3. 服务器的端口号。

4. 连接选项,例如SSL/TLS证书等。

5. 回调函数,用于处理连接状态和接收数据。

通过提供这些信息,lws_client_connect_via_info函数可以建立一个客户端连接,并在连接建立后调用回调函数来处理连接状态和接收数据。

(4)lws_service:处理所有未处理的事件和数据

        在libwebsockets库中,lws_service是一个函数,它用于处理所有未处理的事件和数据。它在一个无限循环中运行,不断地检查是否有新的事件或数据需要处理。当有新的事件或数据到达时,它会调用相应的回调函数来处理它们。lws_service函数是libwebsockets库中最重要的函数之一,它确保了网络连接的稳定和可靠性。

(5)lws_callback_on_writable:设置服务器可以向客户端发送数据

        lws_callback_on_writable 是 libwebsockets 库中的一个函数,它的含义是将一个 websocket 连接的 writable 回调函数加入到事件循环中。当该连接的网络缓冲区变为空闲状态时,就会触发这个回调函数。这个函数通常用于在 websocket 连接中发送数据。调用该函数可以确保在网络缓冲区可写时立即发送数据,从而提高网络传输效率。

(6)常用的结构体

    struct lws                                         // websocket连接句柄
    struct lws_context                           // websocket处理器
    struct lws_context_creation_info    // context参数
    struct lws_protocols                        // 协议层传输句柄
    void* m_pUser;                               // 返回回调的对象
    struct lws_client_connect_info        // 连接参数

2、服务器

以下是使用libwebsockets编写WebSocket服务器的简单步骤:

(1)安装libwebsockets库:您可以从官方网站(https://libwebsockets.org/)下载最新版本的库。

可以通过以下命令安装libwebsockets库:

sudo apt-get install libwebsockets-dev

(2)创建WebSocket服务器

基本的步骤:

a. 创建一个libwebsocket_context对象,该对象将管理所有客户端连接。

b. 设置服务器的协议和端口号。

c. 创建一个回调函数,该函数将处理来自客户端的消息。

d. 启动服务器并等待客户端连接。

处理客户端连接:当客户端连接到服务器时,您需要编写代码来处理连接。这包括验证客户端身份,处理消息和关闭连接。

发送消息:您可以使用libwebsocket库中的函数向客户端发送消息。

下面是一个简单的WebSocket服务器的代码:

libwebsocket开源库中,lws_service回调函数的参数含义如下:

1. wsi:websocket实例,表示当前正在处理的websocket连接。

2. reason:关闭连接的原因代码。如果连接未关闭,此参数为0。

3. user:用户数据,可以使用lws_callback_on_writable函数设置。

4. in:接收到的数据缓冲区。

5. len:接收到的数据长度。

6. flags:标志位,用于指示连接状态等信息。

7. out:发送数据缓冲区。

8. out_len:发送数据长度。

9. reserved:保留参数,暂时没有使用。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libwebsockets.h>static int callback_http(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
{return 0;
}static int callback_websocket(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
{switch (reason) {case LWS_CALLBACK_ESTABLISHED:printf("WebSocket connection established\n");break;case LWS_CALLBACK_RECEIVE:printf("Received data: %s\n", (char *)in);break;case LWS_CALLBACK_CLOSED:printf("WebSocket connection closed\n");break;default:break;}return 0;
}//注册协议,一种协议,对应一套处理方案(类似驱动中的设备树)
static struct lws_protocols protocols[] = {{"http",callback_http,0,0,},{"websocket",callback_websocket,0,0,},{ NULL, NULL, 0, 0 } /* end of list */
};int main(int argc, char **argv)
{struct lws_context_creation_info info;struct lws_context *context;int port = 9000;memset(&info, 0, sizeof(info));info.port = port;info.protocols = protocols;context = lws_create_context(&info);if (!context) {printf("Error creating WebSocket context\n");return 1;}printf("WebSocket server started on port %d\n", port);while (1) {lws_service(context, 50);}lws_context_destroy(context);return 0;
}

(3)编译和运行服务器

可以使用以下命令编译服务器:

gcc -o server server.c -lwebsockets

然后运行服务器:
 

./server

现在WebSocket服务器已经启动了,可以使用浏览器或其他WebSocket客户端连接到它。

以上是使用libwebsockets库创建WebSocket服务器的简单教程,希望对你有所帮助。

3、客户端

(1)基本步骤:

A. 在代码中引入libwebsocket库的头文件:

#include <libwebsockets.h>

B. 创建一个lws_context对象,用于管理WebSocket连接:

struct lws_context* context;

C. 定义连接参数结构体,并设置连接信息:

struct lws_client_connect_via_info connect_info = {.context = context,.address = "192.168.12.226",.port = 8081,.path = "/",.host = "192.168.12.226",.origin = "http://192.168.12.226",.protocol = NULL,.user = NULL,.password = NULL
};

D. 使用lws_client_connect_via_info()函数连接到WebSocket服务器:

lws* ws_client = lws_client_connect_via_info(&connect_info);

E. 在连接成功后,可以使用lws_write()函数向服务器发送消息:

char *message = "Hello, WebSocket Server!";
lws_write(ws_client, (unsigned char *)message, strlen(message), LWS_WRITE_TEXT);

F. 最后,在程序结束时,使用lws_context_destroy()函数释放资源:

lws_context_destroy(context);

(2)以下是使用libwebsockets库创建一个基本的WebSocket客户端的示例代码:

lws_client_connect_via_info 是一个函数,用于通过给定的连接信息连接到 WebSocket 服务器。它接受一个指向连接信息结构体的指针作为参数,并返回一个指向连接句柄的指针。连接信息结构体包含有关连接的所有必要信息,例如服务器的地址、端口号、协议等。使用该函数可以方便地连接到 WebSocket 服务器并开始进行通信。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libwebsockets.h>static int callback_websocket(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len)
{switch (reason) {case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:fprintf(stderr, "Error connecting to server\n");break;case LWS_CALLBACK_CLIENT_ESTABLISHED:fprintf(stderr, "Connected to server\n");break;case LWS_CALLBACK_CLIENT_RECEIVE:fprintf(stderr, "Received data: %s\n", (char *)in);break;case LWS_CALLBACK_CLOSED:fprintf(stderr, "Disconnected from server\n");break;default:break;}return 0;
}int main(int argc, char **argv)
{struct lws_context *context;struct lws *websocket;struct lws_client_connect_info connect_info;memset(&connect_info, 0, sizeof(connect_info));connect_info.context = context;connect_info.address = "localhost";connect_info.port = 8000;connect_info.path = "/";connect_info.host = connect_info.address;connect_info.origin = connect_info.address;connect_info.protocol = NULL;connect_info.ssl_connection = 0;struct lws_protocols protocols[] = {{ "default", callback_websocket, 0, 0 },{ NULL, NULL, 0, 0 }};context = lws_create_context(NULL, NULL, protocols, NULL, NULL, NULL, NULL, -1, -1, 0);if (context == NULL) {fprintf(stderr, "Error creating context\n");return 1;}websocket = lws_client_connect_via_info(&connect_info);if (websocket == NULL) {fprintf(stderr, "Error connecting to server\n");return 1;}while (lws_service(context, 0) >= 0);lws_context_destroy(context);return 0;
}

这个示例代码创建了一个WebSocket客户端,连接到本地主机的8000端口,并打印收到的任何数据。您可以将connect_info.address和connect_info.port更改为连接到其他WebSocket服务器。

在main()函数中,我们首先设置连接信息结构体connect_info,然后创建一个lws_context对象。接下来,我们调用lws_client_connect_via_info()连接到WebSocket服务器,并在while循环中使用lws_service()处理任何传入的数据或事件。最后,我们销毁lws_context对象并返回0,表示程序成功结束。

4、踩到的一些坑

(1)编译时候,会报错说:libwebsocket库 中lws-misc.h 变量humanize_schema_si,未知大小。

解决方法:正常这个是在linux编译器的时候不会报错,但是vs会报错。应该是vs的安全性和语法检查规则导致的。

所以windows编译器时候,改一下就好了。

 (2)客户端连接服务器的名称,记得要和服务器的名称一致,否则连不上。

这篇关于【C++】libwebsockets库的简易教程(附源码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/212838

相关文章

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C

深度解析Spring AOP @Aspect 原理、实战与最佳实践教程

《深度解析SpringAOP@Aspect原理、实战与最佳实践教程》文章系统讲解了SpringAOP核心概念、实现方式及原理,涵盖横切关注点分离、代理机制(JDK/CGLIB)、切入点类型、性能... 目录1. @ASPect 核心概念1.1 AOP 编程范式1.2 @Aspect 关键特性2. 完整代码实

C++链表的虚拟头节点实现细节及注意事项

《C++链表的虚拟头节点实现细节及注意事项》虚拟头节点是链表操作中极为实用的设计技巧,它通过在链表真实头部前添加一个特殊节点,有效简化边界条件处理,:本文主要介绍C++链表的虚拟头节点实现细节及注... 目录C++链表虚拟头节点(Dummy Head)一、虚拟头节点的本质与核心作用1. 定义2. 核心价值二

C++ 检测文件大小和文件传输的方法示例详解

《C++检测文件大小和文件传输的方法示例详解》文章介绍了在C/C++中获取文件大小的三种方法,推荐使用stat()函数,并详细说明了如何设计一次性发送压缩包的结构体及传输流程,包含CRC校验和自动解... 目录检测文件的大小✅ 方法一:使用 stat() 函数(推荐)✅ 用法示例:✅ 方法二:使用 fsee