文章目录

  • 前言
  • 一、libwebsockets是什么?
  • 二、使用到的资源
  • 三、编译
    • 1. cmake
    • 2. libwebsockets
  • 四、 使用示例
    • 做客户端
    • 测试

前言

本文主要介绍libwebsockets在linux下的交叉编译,及demo例程的简单使用。


一、libwebsockets是什么?

官方回答:Libweb套接字 (LWS)是一个灵活、轻量级的纯C库,可使用非阻塞事件循环以极小的内存占用轻松实现现代网络协议。自2010年以来,它一直在不断开发,并被全球数千万设备和数千名开发人员使用。

二、使用到的资源

  1. cmake源码:https://download.csdn.net/download/m0_46592311/87558003
  2. libwebsockets源码:https://download.csdn.net/download/m0_46592311/87557999
  3. websocket测试工具:https://download.csdn.net/download/m0_46592311/87558013

三、编译

1. cmake

需修改cmake/CMakeLists.txt,在其中添加set(CMAKE_USE_OPENSSL OFF),可以直接添加到文件首行, 这里具体位置应该没有要求。用于解决没有openssl的问题。

步骤:

./configure sudo makesudo make install

2. libwebsockets

由于用不到SSL功能,所以将配置项libwebsockets-main/CMakeLists.txt 中的LWS_WITH_SSL注释掉。

步骤:

cd libwebsockets-main
mkdir build
sudo cmake ..
sudo make
sudo make install
sudo ldconfig

四、 使用示例

做客户端

static int interrupted;/* one of these created for each message */struct msg
{char payload[40960 * 2]; /* is malloc'd */size_t len;
};#define MAX_PAYLOAD_SIZE 1024struct lws_rx
{unsigned char databuf[MAX_PAYLOAD_SIZE];int len;char rxflag;   // 接收标志char txflag;   // 待发送标志char txedflag; // 已发送标志int idcount;
};struct per_vhost_data__minimal
{struct lws_context *context;struct lws_vhost *vhost;const struct lws_protocols *protocol;pthread_t pthread_spam[2];lws_sorted_usec_list_t sul;struct lws_client_connect_info i;struct lws *client_wsi;int counter;char finished;char established;
};struct per_vhost_data__minimal data_minimal;struct msg amsg;       // 消息发送结构体
struct lws_rx lwsrx_buf; // 消息接收结构体int jc_respond = 0; //// 等待websocket响应
int lws_response(void)
{if ((lwsrx_buf.txedflag == 0) && (lwsrx_buf.txflag == 0))return 1;int timeout = 10 * 1000 / 200; // 超时等待时间为10秒while (timeout--){if (lwsrx_buf.rxflag == 1) // 收到了数据应答{// lws_rxcontrol(lwsrx_buf); //解析RX接收内容lwsrx_buf.txflag = 0;lwsrx_buf.txedflag = 0;lwsrx_buf.rxflag = 0;return 1;}usleep(200 * 1000); // 200ms间抽一次接收数据}printf("ws响应超时!-------------------------------------.\n");return 0;
}static void *thread_spam(void *d)
{struct per_vhost_data__minimal *vhd =(struct per_vhost_data__minimal *)d;int len = 40960 * 2, index = 1, n, whoami = 0;int TimeCnt = 0; // 计数std::string str_DevMsg;do{//         /* don't generate output if client not connected */if (!vhd->established){lwsl_user("websocket链接还未建立!\n");goto wait;}lwsl_user("ws填充发送数据内容.\n");n = lws_snprintf((char *)amsg.payload + LWS_PRE, (unsigned int)len,"发送第%d条数据\n", TimeCnt);amsg.len = (unsigned int)n;lwsl_user("ws数据长度 %d.\n", amsg.len);lwsrx_buf.txflag = 1;/** This will cause a LWS_CALLBACK_EVENT_WAIT_CANCELLED* in the lws service thread context.*/lws_cancel_service(vhd->context);lws_response(); // 等待响应及数据解析wait:sleep(10);TimeCnt++;} while (!vhd->finished);lwsl_notice("thread_spam %d exiting\n", whoami);pthread_exit(NULL);return NULL;
}/** The retry and backoff policy we want to use for our client connections*/static const uint32_t backoff_ms[] = {1000, 2000, 3000, 4000, 5000};static const lws_retry_bo_t retry = {.retry_ms_table = backoff_ms,.retry_ms_table_count = LWS_ARRAY_SIZE(backoff_ms),.conceal_count = LWS_ARRAY_SIZE(backoff_ms) + 10,.secs_since_valid_ping = 30,      /* force PINGs after secs idle */.secs_since_valid_hangup = 30 + 30, //;//35, /* hangup after secs idle */.jitter_percent = 20,
};static void
sul_connect_attempt(struct lws_sorted_usec_list *sul)
{struct per_vhost_data__minimal *vhd =lws_container_of(sul, struct per_vhost_data__minimal, sul);vhd->i.context = vhd->context;vhd->i.port = 5437;               vhd->i.address = "192.168.1.100"; string path = "/ws";vhd->i.path = path.c_str();vhd->i.host = vhd->i.address;vhd->i.origin = vhd->i.address;vhd->i.ssl_connection = 0;vhd->i.iface = NULL;vhd->i.protocol = "lws-minimal-broker";vhd->i.pwsi = &vhd->client_wsi;vhd->i.retry_and_idle_policy = &retry;lwsl_user("%s: 连接Ws服务器\n", __func__);if (!lws_client_connect_via_info(&vhd->i))lws_sul_schedule(vhd->context, 0, &vhd->sul,sul_connect_attempt, 10 * LWS_US_PER_SEC);
}static int
callback_minimal_broker(struct lws *wsi, enum lws_callback_reasons reason,void *user, void *in, size_t len)
{struct per_vhost_data__minimal *vhd =(struct per_vhost_data__minimal *)lws_protocol_vh_priv_get(lws_get_vhost(wsi),lws_get_protocol(wsi));const struct msg *pmsg = &amsg;void *retval;int n, m, r = 0;switch (reason){/* --- protocol lifecycle callbacks --- */case LWS_CALLBACK_PROTOCOL_INIT:lwsl_user("%s: LWS_CALLBACK_PROTOCOL_INIT\n", __func__);vhd = (struct per_vhost_data__minimal *)lws_protocol_vh_priv_zalloc(lws_get_vhost(wsi),lws_get_protocol(wsi),sizeof(struct per_vhost_data__minimal));vhd->context = lws_get_context(wsi);vhd->protocol = lws_get_protocol(wsi);vhd->vhost = lws_get_vhost(wsi);/* start the content-creating threads */lwsl_user("%s: start the content-creating threads\n", __func__);if (pthread_create(&vhd->pthread_spam[0], NULL, thread_spam, vhd)){lwsl_err("thread creation failed\n");r = 1;goto init_fail;}sul_connect_attempt(&vhd->sul);break;case LWS_CALLBACK_PROTOCOL_DESTROY:lwsl_err("CLIENT_CONNECTION_ERROR\n");init_fail:vhd->finished = 1;pthread_join(vhd->pthread_spam[0], &retval);lws_sul_cancel(&vhd->sul);return r;case LWS_CALLBACK_CLIENT_CONNECTION_ERROR:lwsl_err("CLIENT_CONNECTION_ERROR: %s\n",in ? (char *)in : "(null)");vhd->client_wsi = NULL;lws_sul_schedule(vhd->context, 0, &vhd->sul,sul_connect_attempt, LWS_US_PER_SEC);break;/* --- client callbacks --- */case LWS_CALLBACK_CLIENT_ESTABLISHED:lwsl_user("%s: established\n", __func__);vhd->established = 1;break;case LWS_CALLBACK_CLIENT_RECEIVE:lwsl_user("RX: %s\n", (const char *)in);if (len < MAX_PAYLOAD_SIZE){memcpy(lwsrx_buf.databuf, in, len); // 拷贝数据lwsrx_buf.rxflag = 1;             // 收到数据标志lwsrx_buf.len = len;}break;case LWS_CALLBACK_CLIENT_WRITEABLE:lwsl_user("%s: LWS_CALLBACK_CLIENT_WRITEABLE\n", __func__);if (lwsrx_buf.txflag == 0) // 无数据待发送{lwsl_user("%s: 无数据需要发送.\n", __func__);break;}lwsrx_buf.txedflag = 1; // 已发送标志置位lwsrx_buf.txflag = 0;    // 防止重复发送printf("lws_write数据长度:%d\n", pmsg->len);printf("%s\n", (unsigned char *)pmsg->payload);/* notice we allowed for LWS_PRE in the payload already */m = lws_write(wsi, ((unsigned char *)pmsg->payload) + LWS_PRE,pmsg->len, LWS_WRITE_TEXT);if (m < (int)pmsg->len){lwsl_err("ERROR %d writing to ws socket\n", m);return -1;}break;case LWS_CALLBACK_CLIENT_CLOSED:lwsl_user("%s: LWS_CALLBACK_CLIENT_CLOSED\n", __func__);vhd->client_wsi = NULL;vhd->established = 0;lws_sul_schedule(vhd->context, 0, &vhd->sul,sul_connect_attempt, LWS_US_PER_SEC);break;case LWS_CALLBACK_EVENT_WAIT_CANCELLED:lwsl_user("%s: LWS_CALLBACK_EVENT_WAIT_CANCELLED\n", __func__);/** When the "spam" threads add a message to the ringbuffer,* they create this event in the lws service thread context* using lws_cancel_service().** We respond by scheduling a writable callback for the* connected client, if any.*/if (vhd && vhd->client_wsi && vhd->established)lws_callback_on_writable(vhd->client_wsi);break;default:break;}return lws_callback_http_dummy(wsi, reason, user, in, len);
}static const struct lws_protocols protocols[] = {{"lws-minimal-broker",callback_minimal_broker,0, 0, 0, NULL, 0},LWS_PROTOCOL_LIST_TERM};// 启动websocket,断线重连
void *t_WebSocketOpenRun(void *para)
{printf("websocket初始化.\n");sleep(10); // 开机等10秒,等待4G拨号先,当然该程序不存在先后struct lws_context_creation_info info;struct lws_context *context;const char *p;int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE/* for LLL_ verbosity above NOTICE to be built into lws,* lws must have been configured and built with* -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE *//* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER *//* | LLL_EXT */ /* | LLL_CLIENT */   /* | LLL_LATENCY *//* | LLL_DEBUG */;lws_set_log_level(logs, NULL);lwsl_user("LWS minimal ws client tx\n");lwsl_user("  Run minimal-ws-broker and browse to that\n");memset(&info, 0, sizeof info);     /* otherwise uninitialized garbage */info.port = CONTEXT_PORT_NO_LISTEN; /* we do not run any server */info.protocols = protocols;/** since we know this lws context is only ever going to be used with* one client wsis / fds / sockets at a time, let lws know it doesn't* have to use the default allocations for fd tables up to ulimit -n.* It will just allocate for 1 internal and 1 (+ 1 http2 nwsi) that we* will use.*/info.fd_limit_per_thread = 1 + 1 + 1;context = lws_create_context(&info);if (!context){lwsl_err("lws init failed\n");return;}while (n >= 0 && !interrupted){n = lws_service(context, 0);}lws_context_destroy(context);lwsl_user("Completed\n");return;
}

测试

用网线连接电脑和树莓派

树莓派linux交叉编译libwebsocket及使用示例相关推荐

  1. 树莓派Linux内核源码配置、编译、挂载(boot/kernal/根文件)、开启新内核

    目录 一.树莓派Linux源码配置(适合树莓派) 总体概述 配置的三种方式 1.照搬厂家的配置(使用这种方式) 2.参考厂家的配置(感受一下) 3.完全自主配置(需要一定工作经验) 二.树莓派Linu ...

  2. Liunx树莓派(ARM)开发篇—第十四章、树莓派Linux内核编译步骤(超详细、图文结合)

    对树莓派内核源码进行配置后,下一步要进行树莓派Linux内核编译 以下步骤均在PC端虚拟机上完成 准备材料:PC端虚拟机.树莓派交叉编译工具.树莓派内核(交叉编译工具.内核下载步骤见树莓派内核源码) ...

  3. 树莓派学习笔记(九)树莓派Linux内核开发

    一.树莓派Linux源码配置 1.概念: 驱动代码的编译需要一个提前编译好的内核,想要编译内核就必须先配置 配置的最终目标会生成 .config文件,该文件指导Makefile去把有用东西组织成内核 ...

  4. 树莓派-linux内核编译

    树莓派-linux内核编译 装虚拟机[^1] 配置共享文件夹 配置交叉编译工具 下载树莓派linux系统内核[^3] 树莓派等芯片带操作系统的启动过程 树莓派linux源码目录树 树莓派linux源码 ...

  5. Linux树莓派开发——配置树莓派内核源码,内核编译,更换树莓派Linux内核

    目录 一.树莓派Linux源码配置 1.配置的三种方法 2.内核源码的下载 二.树莓派内核编译 1.树莓派的编译 ​2.生成vmlinux 三.更换树莓派内核的详细步骤 一.树莓派Linux源码配置 ...

  6. conan入门(五):conan 交叉编译引用第三方库示例

    conan 交叉编译引用第三方库示例 Conan 是 C 和 C++ 语言的依赖项和包管理器.它是免费和开源的,适用于所有平台(Windows.Linux.OSX.FreeBSD.Solaris 等) ...

  7. 树莓派开发 --- 交叉编译工具

    文章目录 1.交叉编译的概念 2.树莓派的交叉编译 2.1.交叉编译工具的下载 2.2.交叉编译工具导入环境变量 2.3.带WiringPi的交叉编译 1.交叉编译的概念 交叉编译是指在一个平台上编译 ...

  8. Linux 交叉编译简介

    Linux 交叉编译简介 主机,目标,交叉编译器 主机与目标 编译器是将源代码转换为可执行代码的程序.像所有程序一样,编译器运行在特定类型的计算机上,输出的新程序也运行在特定类型的计算机上. 运行编译 ...

  9. Arm Linux 交叉编译(交叉编译是什么?CROSS_COMPILE)(交叉编译工具链【待更】)

    文章目录 交叉编译 1.编译 2.本地编译 3.交叉编译 交叉编译工具链 交叉编译 在嵌入式系统开发中,经常会听到一个词:交叉编译.到底什么是"交叉编译"呢?为什么要使用" ...

最新文章

  1. eclipse中使用svn提交,更新代码。
  2. Leetcode1713. 得到子序列的最少操作次数[C++题解]:LCS转化成LIS,转化为nlogn做法
  3. 大道至简—GO语言最佳实践
  4. android linearllayout 隐藏 动画,AnimatedLinearLayout:带删除动画的LinearLayout
  5. 服务器自动删文件,服务器定时删除文件工具
  6. Android与服务器通信之socket通信
  7. linux查询hive sql输出文件,数据库-如何将HiveQL查询的结果输出到CSV?
  8. 隐马尔可夫模型模型评估及最优路径的matlab实现
  9. 免费数据集下载网站【dataset】
  10. 简单工厂模式学习总结
  11. 哈夫曼树与哈夫曼编码
  12. c语言看门狗的作用,AT89S52单片机看门狗C语言程序
  13. 基础知识点|命令执行漏洞相关总结
  14. 中国近代史纲要考研选择题
  15. MT6323详细芯片资料分享 MT6323设计原理图须知
  16. 5.14 按照字体颜色对已拓展的客户数进行排序 [原创Excel教程]
  17. 快来开建春晚红包信息群吧!
  18. Excel数据透视表排序
  19. 开源项目之Android繁体中文输入法
  20. python可视化窗口库_Python可视化工具介绍——找到合适的库

热门文章

  1. the number of input partition columns (1) doesn‘t equal to table‘s partition columns (2)
  2. RFID系统工作原理
  3. 如何实现Thinkphp的日志写入
  4. Unity 烘焙灯光贴图,跳转场景时会黑一下问题
  5. 批处理命令之精确获取操作系统版本信息
  6. 经验分享2-火狐浏览器下载中文名文件乱码解决办法
  7. 闭环步进与伺服电机差异
  8. Arduino空气质量监测仪
  9. 真正的ps切图方法(前端必看)
  10. python程序:学校考勤系统