IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> mongoose:轻量的跨平台通讯库(websocket + protobuf) -> 正文阅读

[网络协议]mongoose:轻量的跨平台通讯库(websocket + protobuf)

mongoose集成在项目中,主要还是因为轻量,而且方便。一个.h和一个.c文件就OK。其次,mongoose的封装也不错,使用简单。
本文以mongoose websocket client 及Qt- QWebSocketServer 为例。

server端:

#include <QCoreApplication>
#include <QtWebSockets/QWebSocketServer>
#include <QDebug>
#include <QWebSocket>

struct A{
    int a;
    double b;
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QWebSocketServer server(QString("WSSERVER"),QWebSocketServer::NonSecureMode);
    server.listen(QHostAddress::Any,8000);

    QObject::connect(&server,&QWebSocketServer::newConnection,[&server](){
        QWebSocket *pSocket = server.nextPendingConnection();
        qDebug() << "Client connected:" << pSocket->peerName() << pSocket->origin();
		
		/// 接收文本数据
        QObject::connect(pSocket, &QWebSocket::textMessageReceived,
                [](const QString &message){
            qDebug() << __FUNCTION__ << __LINE__ << message;

        });
        
        /// 接收二进制数据
        QObject::connect(pSocket, &QWebSocket::binaryMessageReceived,
                  [](const QByteArray &message){
            qDebug() << "----------------------------------------";
            qDebug() << __FUNCTION__ << __LINE__ << message;
            struct A* obja = (A*)message.data();
            qDebug() << obja->a << obja->b << Qt::endl;
        });
        
		/// 监听断开连接信号
        QObject::connect(pSocket, &QWebSocket::disconnected,
                [](){
            qDebug() << "client disconnected;";
        });
    });

    return a.exec();
}

不得不说,基于Qt的QWebsocketServer 创建 ws server端也是很方便。

client 端

#include <QCoreApplication>
#include <QString>

// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
//
// Example Websocket client. Usage:
//    1. Start websocket server: cd ../websocket-server && make
//    2. In another terminal, start this client: make

#include "mongoose.h"

static const char *s_url = "ws://localhost:8000/websocket";

// Print websocket response and signal that we're done
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
    if (ev == MG_EV_ERROR) {
        // On error, log error message
        LOG(LL_ERROR, ("%p %s", c->fd, (char *) ev_data));
    } else if (ev == MG_EV_WS_OPEN) {
        // When websocket handshake is successful, send message

        /// 字符串传输测试 
        char buf[] = "11111111111111111111111111111111111111111111111111111111"
                     "22222222222222222222222222222222222222222222222222222222"
                     "33333333333333333333333333333333333333333333333333333333"
                     "44444444444444444444444444444444444444444444444444444444"
                     "55555555555555555555555555555555555555555555555555555555"
                     "66666666666666666666666666666666666666666666666666666666"
                     "77777777777777777777777777777777777777777777777777777777"
                     "s888888888888888";
        char msg[65535] = {0};
        for(int i = 0;i<150;++i){
            strcat(msg,buf);
        }
        printf(" strlen of msg : strlen = %d %s\n",strlen(msg),msg);
        mg_ws_send(c, msg, strlen(msg), WEBSOCKET_OP_TEXT);

        /// 二进制数据测试
        ::Sleep(1000);
        struct A{
            int a;
            double b;
        };

        A* obj_a = new A;
        obj_a->a = 10;
        obj_a->b = 13.2;
        mg_ws_send(c,(char*)obj_a,sizeof(A),WEBSOCKET_OP_BINARY);

    } else if (ev == MG_EV_WS_MSG) {
        // When we get echo response, print it
        struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
        printf("GOT ECHO REPLY: [%.*s]\n", (int) wm->data.len, wm->data.ptr);
    }

    if (ev == MG_EV_ERROR || ev == MG_EV_CLOSE || ev == MG_EV_WS_MSG) {
        *(bool *) fn_data = true;  // Signal that we're done
    }
}

int main(void) {
    struct mg_mgr mgr;        // Event manager
    bool done = false;        // Event handler flips it to true
    struct mg_connection *c;  // Client connection
    mg_mgr_init(&mgr);        // Initialise event manager
    c = mg_ws_connect(&mgr, s_url, fn, &done, NULL);     // Create client
    while (c && done == false) mg_mgr_poll(&mgr, 1000);  // Wait for echo
    mg_mgr_free(&mgr);                                   // Deallocate resources
    return 0;
}

mongoose websocket client 端的实现也很简单,mg_ws_connect 注册消息回调事件,mg_ws_send 可以用于发送指定的文本或者二进制数据。

plus Protobuf

上一篇 Protobuf编译 中记录了protobuf的编译方法,下面我们说说protobuf的使用。

1、编写 .proto 文件

syntax = "proto3";
package WS;
option optimize_for = LITE_RUNTIME;

message req_login
{
    string username = 1;
    string password = 2;
}

2、编译.proto文件,生成对应的.h 和.cpp 文件

protoc --cpp_out=./ *.proto

3、集成到项目中

以Qt为例。在pro文件中增加如下配置:


INCLUDEPATH += . \
               .. \
               install/include
HEADERS += \
    install/bin/ubasestruct.pb.h

SOURCES += \
        install/bin/ubasestruct.pb.cc \

#  添加protobuf 静态库文件 
LIBS += -L$$PWD/install/lib/ -llibprotobufd
LIBS += -L$$PWD/install/lib/ -llibprotocd
LIBS += -L$$PWD/install/lib/ -llibprotobuf-lited

INCLUDEPATH += $$PWD/install/lib
DEPENDPATH += $$PWD/install/lib

对应的server 端接收数据反序列化 例如:

#include <QCoreApplication>
#include <QtWebSockets/QWebSocketServer>
#include <QDebug>
#include <QWebSocket>
#include "install/bin/ubasestruct.pb.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QWebSocketServer server(QString("WSSERVER"),QWebSocketServer::NonSecureMode);
    server.listen(QHostAddress::Any,8000);

    QObject::connect(&server,&QWebSocketServer::newConnection,[&server](){
        QWebSocket *pSocket = server.nextPendingConnection();

        qDebug() << "Client connected:" << pSocket->peerName() << pSocket->origin();

        QObject::connect(pSocket, &QWebSocket::textMessageReceived,
                [](const QString &message){
            qDebug() << __FUNCTION__ << __LINE__ << message;

        });
        QObject::connect(pSocket, &QWebSocket::binaryMessageReceived,
                  [](const QByteArray &message){
            qDebug() << __FUNCTION__ << __LINE__ << message;

		   // protobuf 数据反序列化
           WS::req_login rsp2{};
           if (!rsp2.ParseFromArray(message,message.count())) {
               std::cout << "parse error\n";
               return;
           }
           std::cout << rsp2.username() << " <=====>  " << rsp2.password() << std::endl;
        });
        QObject::connect(pSocket, &QWebSocket::disconnected,
                [](){
            qDebug() << "client disconnected;";
        });
    });

    return a.exec();
}

mongoose 客户端数据进行序列化:

#include <QCoreApplication>
#include <QString>
#include "install/bin/ubasestruct.pb.h"


// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved
//
// Example Websocket client. Usage:
//    1. Start websocket server: cd ../websocket-server && make
//    2. In another terminal, start this client: make

#include "mongoose.h"

static const char *s_url = "ws://localhost:8000/websocket";

// Print websocket response and signal that we're done
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
    if (ev == MG_EV_ERROR) {
        // On error, log error message
        LOG(LL_ERROR, ("%p %s", c->fd, (char *) ev_data));
    } else if (ev == MG_EV_WS_OPEN) {
        // When websocket handshake is successful, send message

        /// 字符串传输测试
        char buf[] = "11111111111111111111111111111111111111111111111111111111"
                     "22222222222222222222222222222222222222222222222222222222"
                     "33333333333333333333333333333333333333333333333333333333"
                     "44444444444444444444444444444444444444444444444444444444"
                     "55555555555555555555555555555555555555555555555555555555"
                     "66666666666666666666666666666666666666666666666666666666"
                     "77777777777777777777777777777777777777777777777777777777"
                     "s888888888888888";
        char msg[65535] = {0};
        for(int i = 0;i<150;++i){
            strcat(msg,buf);
        }
        printf(" strlen of msg : strlen = %d %s\n",strlen(msg),msg);
        mg_ws_send(c, msg, strlen(msg), WEBSOCKET_OP_TEXT);

        /// 二进制数据测试 ==》 发送protobuf数据
        WS::req_login req;
        req.set_username(std::string(msg));
        req.set_password("12222222");

        int sizeArray        = req.ByteSizeLong();
        QByteArray * qbArray = new QByteArray[sizeArray];
        req.SerializeToArray(qbArray,sizeArray);
        mg_ws_send(c,(char*)qbArray,sizeArray,WEBSOCKET_OP_BINARY);
        
    } else if (ev == MG_EV_WS_MSG) {
        // When we get echo response, print it
        struct mg_ws_message *wm = (struct mg_ws_message *) ev_data;
        printf("GOT ECHO REPLY: [%.*s]\n", (int) wm->data.len, wm->data.ptr);
    }

    if (ev == MG_EV_ERROR || ev == MG_EV_CLOSE || ev == MG_EV_WS_MSG) {
        *(bool *) fn_data = true;  // Signal that we're done
    }
}

常用的序列化和反序列化API :

说明序列化反序列化
数组的序列化和反序列化bool ParseFromArray(const void* data, int size);bool SerializeToArray(void* data, int size) const;
C++ String的序列化和反序列化bool SerializeToString(string* output) const;bool ParseFromString(const string& data);
文件描述符序列化和反序列化bool SerializeToFileDescriptor(int file_descriptor) const;bool ParseFromFileDescriptor(int file_descriptor);
C++ stream 序列化和反序列化bool SerializeToOstream(ostream* output) const;bool ParseFromIstream(istream* input);
code stream的序列化和反序列化SerializeToCodedStreamParseFromCodedStream
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2022-04-07 23:04:59  更:2022-04-07 23:05:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 4:29:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码