封装利用libwebsockets写出的客户端、服务端程序为客户端服务端类


文章目录

  • 封装利用libwebsockets写出的客户端、服务端程序为客户端服务端类
    • 1.封装
    • 2.封装后写wss客户端、服务端
    • 3.测试结果
    • 4.客户端、服务端类程序

1.封装

我们后续将使用c++来开发程序,因此有必要将用c写成的wss客户端、服务端程序作进一步封装,使其成为wss客户端类和服务端类,这样更便于调用。封装后的程序结构:

ubuntu@ubuntu-virtual-machine:~/work/test_libwebsockets/lws_class$ tree
.
├── client
│   ├── client
│   ├── compile.sh
│   ├── lws_client.cpp
│   ├── lws_client.h
│   └── test.cpp
└── server├── compile.sh├── lws_server.cpp├── lws_server.h├── server└── test.cpp2 directories, 10 files

2.封装后写wss客户端、服务端

封装后写wss客户端和服务端将非常方便,只需要几行即可创建一个客户端或者服务端:

服务端创建测试程序:

#include "lws_server.h"
#include <signal.h>static int interrupted;void sigint_handler(int sig)
{interrupted = 1;
}int main(int argc,char **argv)
{//接收SIGINT(ctrl+c)信号signal(SIGINT, sigint_handler);int n = 0;//创建服务器对象(可以指定端口,这里指定了8000)lws_server server(8000);//初始化服务器server.init();lwsl_notice("port:%d\n",server.get_port());//设置ssl(不使用ssl则传空,使用则传入证书文件路径)server.set_ssl(NULL,NULL,NULL,0);//创建服务器server.create();//服务器运行(运行时可设置间隔等待时间,这里为1000,单位为ms)while(n >= 0 && !interrupted)n = server.run(1000);//销毁资源server.destroy();return 0;
}

客户端创建测试程序:

#include "lws_client.h"
#include <signal.h>static int interrupted;void sigint_handler(int sig)
{interrupted = 1;
}int main(int argc,char **argv)
{signal(SIGINT, sigint_handler);int n = 0;//创建客户端对象(传入服务器地址和端口)lws_client client("127.0.0.1",8000);//初始化客户端client.init();//设置sslclient.set_ssl(NULL,NULL,NULL,0);//创建客户端client.create();//连接服务器(需要ssl连接时传入1,否则传0)client.connect(0);//客户端运行while(n >= 0 && !interrupted)n = client.run(1000);//销毁资源client.destroy();return 0;
}

3.测试结果

运行服务端:

ubuntu@ubuntu-virtual-machine:~/work/test_libwebsockets/lws_class/server$ ./server
[2018/09/12 18:34:56:3472] NOTICE: port:8000
[2018/09/12 18:34:56:3493] NOTICE: Creating Vhost 'default' port 8000, 1 protocols, IPv6 off

运行客户端:

ubuntu@ubuntu-virtual-machine:~/work/test_libwebsockets/lws_class/client$ ./client
[2018/09/12 18:35:43:4919] NOTICE: Creating Vhost 'default' (serving disabled), 1 protocols, IPv6 off
[2018/09/12 18:35:43:4947] NOTICE: Connected to server ok!
[2018/09/12 18:35:43:4964] NOTICE: Tx: 你好 1
[2018/09/12 18:35:43:4987] NOTICE: Tx: 你好 2
[2018/09/12 18:35:43:4994] NOTICE: Rx: 你好 1
[2018/09/12 18:35:43:4999] NOTICE: Rx: 你好 2
[2018/09/12 18:35:43:5000] NOTICE: Tx: 你好 3
[2018/09/12 18:35:43:5007] NOTICE: Rx: 你好 3

服务端:

ubuntu@ubuntu-virtual-machine:~/work/test_libwebsockets/lws_class/server$ ./server
[2018/09/12 18:34:56:3472] NOTICE: port:8000
[2018/09/12 18:34:56:3493] NOTICE: Creating Vhost 'default' port 8000, 1 protocols, IPv6 off
[2018/09/12 18:35:43:4939] NOTICE: Client connect!
[2018/09/12 18:35:43:4979] NOTICE: recvied message:你好 1
[2018/09/12 18:35:43:4989] NOTICE: recvied message:你好 2
[2018/09/12 18:35:43:5001] NOTICE: recvied message:你好 3

测试通信成功。目前服务器为回显服务器,其底层采用的poll机制。

4.客户端、服务端类程序

服务端程序类:

#include "lws_server.h"#define MAX_PAYLOAD_SIZE  (10 * 1024)static struct lws_context_creation_info ctx_info = { 0 };
static struct lws_context *context = NULL;/*** 会话上下文对象,结构根据需要自定义*/
struct session_data {int msg_count;unsigned char buf[LWS_PRE + MAX_PAYLOAD_SIZE];int len;bool bin;bool fin;
};/*
构造函数
*/
lws_server::lws_server(int listen_port)
{port = listen_port;
}/*
析构函数
*/
lws_server::~lws_server()
{lwsl_notice("析构完成\n");
}/*
拷贝构造
*/
lws_server::lws_server(const lws_server &obj)
{}int lws_server::get_port()
{return port;
}/*
服务器底层实现的回调函数
*/
static int protocol_my_callback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{struct session_data *data = (struct session_data *) user;switch ( reason ) {case LWS_CALLBACK_ESTABLISHED:       // 当服务器和客户端完成握手后lwsl_notice("Client connect!\n");break;case LWS_CALLBACK_RECEIVE:           // 当接收到客户端发来的帧以后// 判断是否最后一帧data->fin = lws_is_final_fragment( wsi );// 判断是否二进制消息data->bin = lws_frame_is_binary( wsi );// 对服务器的接收端进行流量控制,如果来不及处理,可以控制之// 下面的调用禁止在此连接上接收数据lws_rx_flow_control( wsi, 0 );// 业务处理部分,为了实现Echo服务器,把客户端数据保存起来memcpy( &data->buf[ LWS_PRE ], in, len );data->len = len;lwsl_notice("recvied message:%s\n",&data->buf[ LWS_PRE ]);// 需要给客户端应答时,触发一次写回调lws_callback_on_writable( wsi );data = NULL;break;case LWS_CALLBACK_SERVER_WRITEABLE:   // 当此连接可写时lws_write( wsi, &data->buf[ LWS_PRE ], data->len, LWS_WRITE_TEXT );// 下面的调用允许在此连接上接收数据lws_rx_flow_control( wsi, 1 );break;}// 回调函数最终要返回0,否则无法创建服务器return 0;
}/*** 支持的WebSocket子协议数组* 子协议即JavaScript客户端WebSocket(url, protocols)第2参数数组的元素* 你需要为每种协议提供回调函数*/
struct lws_protocols protocols[] = {{//协议名称,协议回调,接收缓冲区大小"ws", protocol_my_callback, sizeof( struct session_data ), MAX_PAYLOAD_SIZE,},{NULL, NULL,   0 // 最后一个元素固定为此格式}
};void lws_server::init()
{ctx_info.port = 8000;ctx_info.iface = NULL; // 在所有网络接口上监听ctx_info.protocols = protocols;ctx_info.gid = -1;ctx_info.uid = -1;ctx_info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;
}int lws_server::set_ssl(const char* ca_filepath, const char* server_cert_filepath,const char*server_private_key_filepath,bool is_support_ssl)
{if(!is_support_ssl){ctx_info.ssl_ca_filepath = NULL;ctx_info.ssl_cert_filepath = NULL;ctx_info.ssl_private_key_filepath = NULL;}else{ctx_info.ssl_ca_filepath = ca_filepath;ctx_info.ssl_cert_filepath = server_cert_filepath;ctx_info.ssl_private_key_filepath = server_private_key_filepath;ctx_info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;//ctx_info.options |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;}return is_support_ssl;
}int lws_server::create()
{context = lws_create_context(&ctx_info);if (!context) {lwsl_err("lws_server create failed\n");return -1;}return 1;
}int lws_server::run(int wait_time)
{return lws_service(context, wait_time);
}void lws_server::destroy()
{lws_context_destroy(context);
}
/******************************************************************************版权所有 (C), 2017-2019, ZY******************************************************************************文 件 名   : lws_server.h版 本 号   : 初稿作    者   : ZY生成日期   : 2018年9月12日 星期三最近修改   :功能描述   : lws_server.cpp 的头文件函数列表   :修改历史   :1.日    期   : 2018年9月12日 星期三作    者   : ZY修改内容   : 创建文件******************************************************************************//*----------------------------------------------** 包含头文件                                   **----------------------------------------------*//*----------------------------------------------** 外部变量说明                                 **----------------------------------------------*//*----------------------------------------------** 外部函数原型说明                             **----------------------------------------------*//*----------------------------------------------** 内部函数原型说明                             **----------------------------------------------*//*----------------------------------------------** 全局变量                                     **----------------------------------------------*//*----------------------------------------------** 模块级变量                                   **----------------------------------------------*//*----------------------------------------------** 常量定义                                     **----------------------------------------------*//*----------------------------------------------** 宏定义                                       **----------------------------------------------*/#ifndef __LWS_SERVER_H__
#define __LWS_SERVER_H__#ifdef __cplusplus
#if __cplusplus
extern "C"{#endif
#endif /* __cplusplus */#include <libwebsockets.h>class lws_server
{private:int port;public:lws_server(int listen_port);~lws_server();lws_server(const lws_server &obj);int get_port();void init();int set_ssl(const char* ca_filepath, const char* server_cert_filepath,const char*server_private_key_filepath,bool is_support_ssl);int create();int run(int wait_time);void destroy();
};#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */#endif /* __LWS_SERVER_H__ */

客户端程序类:

#include "lws_client.h"#define MAX_PAYLOAD_SIZE  10 * 1024static struct lws_context_creation_info ctx_info = { 0 };
static struct lws_context *context = NULL;
static struct lws_client_connect_info conn_info = { 0 };
static struct lws *wsi = NULL;/*** 会话上下文对象,结构根据需要自定义*/
struct session_data {int msg_count;unsigned char buf[LWS_PRE + MAX_PAYLOAD_SIZE];int len;
};/*** 某个协议下的连接发生事件时,执行的回调函数** wsi:指向WebSocket实例的指针* reason:导致回调的事件* user 库为每个WebSocket会话分配的内存空间* in 某些事件使用此参数,作为传入数据的指针* len 某些事件使用此参数,说明传入数据的长度*/
int lws_client_callback( struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len )
{struct session_data *data = (struct session_data *) user;switch ( reason ) {case LWS_CALLBACK_CLIENT_ESTABLISHED:   // 连接到服务器后的回调lwsl_notice( "Connected to server ok!\n" );break;case LWS_CALLBACK_CLIENT_RECEIVE:       // 接收到服务器数据后的回调,数据为in,其长度为lenlwsl_notice( "Rx: %s\n", (char *) in );break;case LWS_CALLBACK_CLIENT_WRITEABLE:     // 当此客户端可以发送数据时的回调if ( data->msg_count < 3 ) {// 前面LWS_PRE个字节必须留给LWSmemset( data->buf, 0, sizeof( data->buf ));char *msg = (char *) &data->buf[ LWS_PRE ];data->len = sprintf( msg, "你好 %d", ++data->msg_count );lwsl_notice( "Tx: %s\n", msg );// 通过WebSocket发送文本消息lws_write( wsi, &data->buf[ LWS_PRE ], data->len, LWS_WRITE_TEXT );}break;default:break;
//            lwsl_notice("not support\n");}return 0;
}/*** 支持的WebSocket子协议数组* 子协议即JavaScript客户端WebSocket(url, protocols)第2参数数组的元素* 你需要为每种协议提供回调函数*/
struct lws_protocols protocols[] = {{//协议名称,协议回调,接收缓冲区大小"ws", lws_client_callback, sizeof( struct session_data ), MAX_PAYLOAD_SIZE,},{NULL, NULL,   0 // 最后一个元素固定为此格式}
};/*
构造函数
*/
lws_client::lws_client(char *_address,int _port)
{server_address = _address;port = _port;
}/*
析构函数
*/
lws_client::~lws_client()
{lwsl_notice("析构完成\n");
}/*
拷贝构造
*/
lws_client::lws_client(const lws_client &obj)
{}/*
初始化
*/
void lws_client::init()
{ctx_info.port = CONTEXT_PORT_NO_LISTEN;ctx_info.iface = NULL;ctx_info.protocols = protocols;ctx_info.gid = -1;ctx_info.uid = -1;
}/*
设置ssl
*/
int lws_client::set_ssl(const char* ca_filepath, const char* server_cert_filepath,const char*server_private_key_filepath,bool is_support_ssl)
{if(!is_support_ssl){ctx_info.ssl_ca_filepath = NULL;ctx_info.ssl_cert_filepath = NULL;ctx_info.ssl_private_key_filepath = NULL;}else{ctx_info.ssl_ca_filepath = ca_filepath;ctx_info.ssl_cert_filepath = server_cert_filepath;ctx_info.ssl_private_key_filepath = server_private_key_filepath;ctx_info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;//ctx_info.options |= LWS_SERVER_OPTION_REQUIRE_VALID_OPENSSL_CLIENT_CERT;}return is_support_ssl;
}/*
创建客户端
*/
int lws_client::create()
{// 创建一个WebSocket处理器context = lws_create_context( &ctx_info );if(!context)return -1;return 0;
}/*
连接客户端
*/
int lws_client::connect(int is_ssl_support)
{char addr_port[256] = { 0 };sprintf(addr_port, "%s:%u", server_address, port & 65535 );// 客户端连接参数conn_info = { 0 };conn_info.context = context;conn_info.address = server_address;conn_info.port = port;if(!is_ssl_support)conn_info.ssl_connection = 0;elseconn_info.ssl_connection = 1;conn_info.path = "./";conn_info.host = addr_port;conn_info.origin = addr_port;conn_info.protocol = protocols[ 0 ].name;// 下面的调用触发LWS_CALLBACK_PROTOCOL_INIT事件// 创建一个客户端连接wsi = lws_client_connect_via_info( &conn_info );if(!wsi)return -1;return 1;
}/*
运行客户端
*/
int lws_client::run(int wait_time)
{lws_service( context, wait_time );/*** 下面的调用的意义是:当连接可以接受新数据时,触发一次WRITEABLE事件回调* 当连接正在后台发送数据时,它不能接受新的数据写入请求,所有WRITEABLE事件回调不会执行*/lws_callback_on_writable( wsi );
}/*
销毁
*/
void lws_client::destroy()
{lws_context_destroy(context);
}
/******************************************************************************版权所有 (C), 2017-2019, ZY******************************************************************************文 件 名   : lws_client.h版 本 号   : 初稿作    者   : ZY生成日期   : 2018年9月12日 星期三最近修改   :功能描述   : lws_client.cpp 的头文件函数列表   :修改历史   :1.日    期   : 2018年9月12日 星期三作    者   : ZY修改内容   : 创建文件******************************************************************************//*----------------------------------------------** 包含头文件                                   **----------------------------------------------*//*----------------------------------------------** 外部变量说明                                 **----------------------------------------------*//*----------------------------------------------** 外部函数原型说明                             **----------------------------------------------*//*----------------------------------------------** 内部函数原型说明                             **----------------------------------------------*//*----------------------------------------------** 全局变量                                     **----------------------------------------------*//*----------------------------------------------** 模块级变量                                   **----------------------------------------------*//*----------------------------------------------** 常量定义                                     **----------------------------------------------*//*----------------------------------------------** 宏定义                                       **----------------------------------------------*/#ifndef __LWS_CLIENT_H__
#define __LWS_CLIENT_H__#ifdef __cplusplus
#if __cplusplus
extern "C"{#endif
#endif /* __cplusplus */#include "libwebsockets.h"class lws_client
{private:char *server_address;int port;public:lws_client(char *lws_server_address,int port);~lws_client();lws_client(const lws_client &obj);void init();int set_ssl(const char* ca_filepath, const char* server_cert_filepath,const char*server_private_key_filepath,bool is_support_ssl);int create();int connect(int is_ssl_support);int run(int wait_time);void destroy();
};#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */#endif /* __LWS_CLIENT_H__ */

封装利用libwebsockets写出的客户端、服务端程序为客户端服务端类相关推荐

  1. wss协议 c 服务器,利用LIBWEBSOCKETS写WS、WSS服务端和客户端

    libwebsockets是一款轻量级用来开发服务器和客户端的C库.按照官方(https://libwebsockets.org/)给出的介绍来看,它不仅支持ws,wss还同时支持http与https ...

  2. 利用libwebsockets写ws、wss服务端和客户端

    服务端: server.c #include "libwebsockets.h" #include <signal.h> #include <string.h&g ...

  3. 用php写出显示客户端ip与服务器ip的代码.,PHP面试题答案

    PHP面试题答案 1.求$a,$b,$c三个数中的最大值和最小值(5分) echo max($a,$b,$c); echo min($a,$b,$c); 2.echo().print().print_ ...

  4. 小规则让你写出漂亮又高效的程序

    以下内容引用自 http://blog.csdn.net/u012175089/article/details/51078360 本文来自肥宝游戏,引用必须保留文末二维码!!! 好几天没写文章了,周一 ...

  5. 写出优雅性能的JAVA程序必须遵守的35个原则

    本文给出35条写出优雅性能的JAVA程序的建议,欢迎收藏! 1.尽量指定类.方法的final修饰符 带有final修饰符的类是不可派生的.在Java核心API中,有许多应用final的例子,例如jav ...

  6. php横向扩展,Tp框架怎样 写才能写出可以横向扩展的程序!

    昨天看了个视频 讲的是架构 那个cto说 做为架构师最 重要的是 设计出 可以横向扩展的程序 也就是说一开始你的程序可以只在一台机器上跑 但是随着用户的增加 你的程序要能 随时能扩展机器 那么对于tp ...

  7. 函数式编程的Java编码实践:利用惰性写出高性能且抽象的代码

    简介: 本文会以惰性加载为例一步步介绍函数式编程中各种概念,所以读者不需要任何函数式编程的基础,只需要对 Java 8 有些许了解即可. 作者 | 悬衡 来源 | 阿里技术公众号 本文会以惰性加载为例 ...

  8. 利用函数写出九九乘法表

    九九乘法表大家应该都熟悉,那么利用函数写一个九九乘法该怎么写呢. 这个是换行带来的效果,打印的时候我们用了%-2d ,目的是为了左对齐,更加美观. #include<stdio.h> vo ...

  9. c语言勾股定理程序流程图,方法总结1.表达算法的方法有自然语言.流程图和基本算法语句三种.先有自然语言.再画流程图.最后才能写出基本算法语句.即程序,——青夏教育精英家教网——...

    考点一:自然语言表示的算法 [内容解读]通过对解决具体问题过程与步骤的分析,体会算法的思想,了解算法的含义:对于某一问题往往可以设计出多种算法,通过选用步骤最少的.结构最好的算法. [命题规律]以选择 ...

最新文章

  1. Lintcode 988解题思路和c++代码
  2. rsync定时任务引起cpu负载高
  3. 哈希表创建哈希表(Hash Table,也叫散列表),是根据键(Key)而直接访问在内存存储位置的数据结构.typedef enum{ HASH_OK-icoding-数据结构-C
  4. CentOS操作系统版本信息查看和隐藏
  5. 陆奇知天命,拒绝巨头选 YC
  6. javascript中在链表中向前(向后)移动n个节点
  7. 16进制编辑器 linux,Tweak - Linux下的16进制编辑器
  8. 使用Visio画各种可视化的流程图之用例图和类图
  9. Allegro静态铜皮避让问题
  10. ACdream - 1069 - 无耻的出题人
  11. r语言算巢式设计方差分析_R语言学习笔记(七):方差分析
  12. [人工智能-深度学习-4]:数据流图与正向传播、动态图与静态图
  13. 取消微信抢票的服务器,微信抢票怎么取消?
  14. redis-GEO地理位置
  15. html5制作线路图,HTML5画一个简单呢好看的电路图
  16. 以太坊是什么? 以及以太坊如何工作的?
  17. 抖音html啥意思,用了这么久的抖音,你知道抖音到底是啥意思吗?
  18. 基于51的单片机GPS定位系统设计
  19. pt->onnx->ncnn(pytorch部署自己训练的模型)
  20. 全国计算机竞赛保送清华,全国数学奥赛金牌、保送清华,别人家的孩子了解一下...

热门文章

  1. 如何使用CDN绕过服务器域名备案
  2. H3C简单的防火墙配置
  3. 天气类APP产品微体验(墨迹天气、中央天气预报、雅虎天气、2345天气王)
  4. Hbuilder X mui 华为真机运行和调试
  5. base64 转各种类型的图片
  6. VMware16安装Win10系统
  7. 关于软考你必须要知道的那些事儿
  8. c#写的印刷厂工程单打印软件
  9. 带你从零玩转云服务器
  10. Product Oriented Recurrence(Codeforces Round #566 (Div. 2)E+矩阵快速幂+欧拉降幂)