websocket的简单使用

大冰的小屋 大冰的小屋     2023-03-31     593

关键词:

WebSocket一种在单个 TCP 连接上进行全双工通讯的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端直接向客户端推送数据而不需要客户端进行请求,在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并允许数据进行双向传送。——- 《维基百科》


最近在项目中使用了WebSocket,开发了一个非常简单的服务器端的小程序,用于接收客户端(前端)发送来的摄像头的图像数据,进行相关的处理(我司的人脸跟踪和属性检测)后,将相应的结果再发送给客户端进行相应的展示(广告推荐)。其实这个程序本来不需要使用WebSocket的,完全在本地进行开发就可以了,但是为了一个好看的界面,因此选择了前端进行界面的设计,也就用到了WebSocket进行双端的通信。
然后去查了下有什么用C++已经封装好的WebSocket,在GitHub上看到了一些开源的项目已经用C++实现了WebSocket,不过又发现Qt也实现了WebSocket,包括QWebSocketServer和QWebSocket,再加上Qt比较不错的信号槽机制可以非常简单的进行事件监听,于是选择使用Qt的WebSocket。但是还是遇到了一些问题。

首先是一开始数据接收速度过慢。客户端发给我的是采样png压缩的图片,由于png是无损压缩,每张图片在250k左右,导致我接收这样的一张图片需要300毫秒左右的时间(由于一张图片太大,一张图片客户端分了多次发送,每次在50毫秒左右)。后来改用了JPEG进行图像压缩,大大减少了传输时间。

再次是Qt的QWebSocket需要设置readBufferSize,如果没有设置,我这里的现象是数据在接收到一段时间后,就不会再接收新的数据。通过阅读Qt的源码,QWebSocket的setReadBufferSize方法最终设置的是TCP Socket的receive buffer,如果socket所在的进程不及时将数据从receive buffer中取出,最终导致receive buffer填满,由于TCP的滑动窗口和拥塞控制,接收端会阻止发送端向其发送数据。(QWebSocket的setReadBufferSize方法官方说明:If the buffer size is limited to a certain size, QWebSocket won’t buffer more than this size of data. Exceptionally, a buffer size of 0 means that the read buffer is unlimited and all incoming data is buffered. This is the default. This option is useful if you only read the data at certain points in time (for example, in a real-time streaming application) or if you want to protect your socket against receiving too much data, which may eventually cause your application to run out of memory.)如果不进行设置,QWebSocket 的read buffer将不受限制,但是导致一次接收过大的数据导致应用程序耗尽了内存。

在接收到数据后进行处理时最好采用多线程的机制去处理,以免影响数据的接收。

#ifndef ATTRIBUTESERVER_H
#define ATTRIBUTESERVER_H

#include <QObject>
#include <QByteArray>
#include <QList>
#include <QPair>

#include <opencv2/opencv.hpp>
#include "attributedetect.h"

QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
QT_FORWARD_DECLARE_CLASS(QWebSocket)

class AttributeServer : public QObject

    Q_OBJECT

public:
    explicit AttributeServer(quint16 port, int frame_count = 10, bool debug = false, QObject *parent = Q_NULLPTR);
    ~AttributeServer();

Q_SIGNALS:
    void closed();

private Q_SLOTS:
    void onNewConnection();
    void processTextMessage(QString message);
    void socketDisconnected();

    void onGetAttribute(QString age, QString sex, QString image);

private:
    QWebSocketServer *m_pWebSocketServer;
    QList<QWebSocket *> m_clients;
    bool m_debug;
    QPair<int, long> m_last_id;
    int m_frame_count;

    AttributeDetect* m_attribute_thread;
    QWebSocket* m_current_clients;
;

#endif // ATTRIBUTESERVER_H
#include "attributeserver.h"

#include <iostream>
#include <algorithm>
#include <string>

#include <QtWebSockets/QWebSocketServer>
#include <QtWebSockets/QWebSocket>
#include <QDebug>
#include <QFile>
#include <QMutex>
#include <QWaitCondition>

#include <opencv2/opencv.hpp>

QMutex g_mutex;
QWaitCondition g_condition;

std::vector<std::string> g_vecImages;

AttributeServer::AttributeServer(quint16 port, int frame_cont, bool bdebug, QObject *parent)
    : QObject(parent),
    m_frame_count(frame_cont),
    m_debug(bdebug),
    m_pWebSocketServer(new QWebSocketServer("Attribute Server", QWebSocketServer::NonSecureMode, this)),
    m_clients()

    if (m_pWebSocketServer->listen(QHostAddress::Any, port)) 
        if (m_debug) 
            qDebug() << "Attribute Server listening on port" << port;
        
        connect(m_pWebSocketServer, &QWebSocketServer::newConnection,
            this, &AttributeServer::onNewConnection);
        connect(m_pWebSocketServer, &QWebSocketServer::closed,
            this, &AttributeServer::closed);
    

    m_last_id.first = -1;
    m_last_id.second = 0;

    m_attribute_thread = NULL;
    m_current_clients = NULL;


AttributeServer::~AttributeServer()

    m_pWebSocketServer->close();
    qDeleteAll(m_clients.begin(), m_clients.end());


void AttributeServer::onNewConnection()

    qDebug() << "new  connection";
    QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();

    connect(pSocket, &QWebSocket::textMessageReceived, this, &AttributeServer::processTextMessage);
    connect(pSocket, &QWebSocket::disconnected, this, &AttributeServer::socketDisconnected);

    quint16 sizes = pSocket->readBufferSize();
    pSocket->setReadBufferSize(640 * 480);

    if (m_attribute_thread == NULL) 
        m_attribute_thread = new AttributeDetect(this, m_frame_count);
        connect(m_attribute_thread, SIGNAL(sendAttribute(QString, QString, QString)), this, SLOT(onGetAttribute(QString, QString, QString)));
        m_attribute_thread->start();
    

    m_current_clients = pSocket;
    m_clients << pSocket;


bool startWith(std::string src, std::string substr)

    if (src.empty() || src.size() < substr.size()) 
        return false;
    

    bool bflag = true;
    for (int i = 0; i < substr.size(); i++)
        if (src[i] != substr[i]) 
            bflag = false;
            break;
        
    

    return bflag;


void AttributeServer::processTextMessage(QString message)

    static std::stringstream buf;
    static long count = 0;

    std::string curr_message = message.toStdString();
    bool bflag = startWith(curr_message, "data:image/jpeg;");

    if (bflag) 
        // 新的数据
        // 先处理掉旧的数据
        std::string str_message = buf.str();
        if (!str_message.empty()) 
            g_mutex.lock();
            if (g_vecImages.size() > 0) 
                g_vecImages.clear();
            
            g_vecImages.push_back(str_message);

            g_condition.wakeAll();
            g_mutex.unlock();
        


        // 清除旧的数据,加入新的数据
        buf = std::stringstream();
        buf << curr_message;

    
    else 
        // 旧的数据
        buf << message.toStdString();
    


void AttributeServer::socketDisconnected()


    QWebSocket *pClient = qobject_cast<QWebSocket*>(sender());

    qDebug() << pClient->errorString();

    if (m_debug) 
        qDebug() << "socketDisconnected: " << pClient;
    
    if (pClient) 
        m_clients.removeAll(pClient);
        pClient->deleteLater();
    


void AttributeServer::onGetAttribute(QString age, QString sex, QString image)

    QString str_send_info = QString("\\"age\\":\\"%1\\",\\"sex\\":\\"%2\\",\\"image\\":\\"%3\\"")
        .arg(age)
        .arg(sex)
        .arg(image);

    QByteArray postData = str_send_info.toUtf8();
    static long count = 0;
    qDebug() << "begin send attribute result " << count++;
    m_current_clients->sendTextMessage(postData);
    m_current_clients->flush();

使用libwebsockets搭建一个简单的websocket服务器

本文讲解如何开发一个简单的WebSocket服务器如果你嫌这两个例子都太简单了,且想了解更多更深的websocket的工作原理,可以看这篇文章:http://lucumr.pocoo.org/2012/9/24/websockets-101/为了让这个例子足够简单,我们将对所有的请求以逆序... 查看详情

websocket的简单入门使用(代码片段)

WebSocketWebSocket介绍Java整合WebSocketSpringBoot整合WebSocketWebSocket介绍1)什么是WebSocket?WebSocket是HTML5一种新的协议。它实现了浏览器与服务器全双工通信(full-duplex)。一开始的握手需要借助HTTP请求完成。WebSocket是真正实现了全双工... 查看详情

websocket的简单使用

WebSocket一种在单个TCP连接上进行全双工通讯的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端直接向客户端推送数据而不需要客户端进行请求,在WebSocketAPI中,浏览器和服务器只需要完成... 查看详情

无法通过 Chrome 扩展连接到使用 Spring 创建的简单 websocket 服务器

】无法通过Chrome扩展连接到使用Spring创建的简单websocket服务器【英文标题】:Cannotconnecttoasimplewebsocketserver,createdwithSpring,throughChromeextension【发布时间】:2020-01-2114:31:47【问题描述】:这里是WebSocket服务器的三个简单组件,在Spring... 查看详情

使用 Websockets 构建一个简单的 SMTP 客户端

】使用Websockets构建一个简单的SMTP客户端【英文标题】:BuildingasimpleSMTPclientusingWebsockets【发布时间】:2014-01-2313:54:20【问题描述】:出于好奇和我的一些实验,我想知道在浏览器上构建STMP客户端需要什么。几年前这几乎是不可... 查看详情

websocket介绍和一个简单的聊天室

WebSocket是什么呢?  WebSocket一种在单个TCP连接上进行全双工通讯的协议。WebSocket通信协议于2011年被IETF定为标准RFC6455,并被RFC7936所补充规范,WebSocketAPI被W3C定为标准。WebSocket是独立的、创建在TCP上的协议,和HTTP的唯一关联是... 查看详情

websocket的简单使用

WebSocket一种在单个TCP连接上进行全双工通讯的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端直接向客户端推送数据而不需要客户端进行请求,在WebSocketAPI中,浏览器和服务器只需要完成... 查看详情

有没有一种简单的方法可以将 Ajax 更改为 WebSocket?

】有没有一种简单的方法可以将Ajax更改为WebSocket?【英文标题】:IsthereaneasywaytochangeAjaxintoWebSocket?【发布时间】:2017-03-1710:07:01【问题描述】:请注意我的要求,我知道如何编写和运行WebSocket服务器。我的问题是,我使用Ajax连... 查看详情

简单的 C# WebSockets 服务器

】简单的C#WebSockets服务器【英文标题】:SimpleC#WebSocketsServer【发布时间】:2011-11-2418:46:18【问题描述】:我正在尝试使用以下内容创建一个简单的WebSockets服务器:namespaceConsoleWebSocketServerclassProgramconststringc_MagicKey="258EAFA5-E914-47DA-9... 查看详情

使用websocket实现消息推送

WebSocket上联系客服功能在项目中很难避免,一般有下面三种实现方式: 使用http的get方式轮询接入第三方IM系统自己的IM系统 基于socket基于websocket第一种方式,最low的,实现简单,但是浪费用户流量;第二种方式,接入简... 查看详情

websocket简单例子

websocket是Html5的一个协议,也就是说距离我们2016年就几年时间,其他原理我就不说了,直接讲例子一、准备材料:1、一个开发工具必须支持javaEE7的,原因是javaEE6或以下不支持websocket,我是使用的开发工具是myeclipse2015,这里给各位百度云... 查看详情

使用websocket实现消息推送

WebSocket上联系客服功能在项目中很难避免,一般有下面三种实现方式:使用http的get方式轮询接入第三方IM系统自己的IM系统基于socket基于websocket第一种方式,最low的,实现简单,但是浪费用户流量;第二种方式,接入简单,功能... 查看详情

一个非常简单的 WebSocket 服务器

】一个非常简单的WebSocket服务器【英文标题】:AreallysimpleWebSocketserver【发布时间】:2011-09-1207:21:31【问题描述】:有人知道同时支持75和76的简单WebSocket服务器吗?我曾经使用phpwebsocket(我有一点php经验),直到Chrome自己更新并... 查看详情

用 c# 制作新的简单 websocket 服务器

】用c#制作新的简单websocket服务器【英文标题】:Makenewsimplewebsocketserverwithc#【发布时间】:2012-03-1516:09:37【问题描述】:我对websocket很陌生,我正在尝试用c#从头开始​​制作一个简单的websocket服务器,有人有简单的样品吗??... 查看详情

PHP 简单的网络套接字

】PHP简单的网络套接字【英文标题】:PHPsimplewebsocket【发布时间】:2021-04-2909:25:39【问题描述】:我在AWS上有一个websocket服务器,目前我正在使用JavaScriptwebsockets连接到它。有没有办法使用PHP连接到websocket服务器(最好没有库)... 查看详情

websocket简单实现(代码片段)

...连接的情况,服务端处理http请求往往占用大量资源,而websocket则能使web端和服务端维持长连接。除此之外,建立长连接亦可以使服务端主动向web端推送消息,从而为项目提供更加丰富的功能。本文面向初次使用go开发web服务端的... 查看详情

使用令牌的 websocket 授权

】使用令牌的websocket授权【英文标题】:websocketauthorizationwithtokens【发布时间】:2014-06-1219:22:30【问题描述】:在我的本地机器上,我正在运行apache服务器(php、mysql)和简单的websocket服务器(c++)。现在我正在尝试使用令牌进... 查看详情

websocket教程springboot+maven整合(目录)

1、大话websocket及课程介绍简介:websocket介绍、使用场景分享、学习课程需要什么基础2、课程技术选型和浏览器兼容讲解简介:简单介绍什么是springboot、socketjs、stompjs,及解决使用浏览器兼容问题3、websocket广播、单播、组播介... 查看详情