1 前言
最近工作中需要基于QT写一个websocket的客户端,因为服务器是用websocketpp做的,所以客户端也采用同一个框架,避免通讯中出现异常。
如果使用websocketpp,必需先安装boost环境。
整个开发环境版本:boost_1_80_0 + vs2017 + QT5.12.8
2 boost编译
2.1 下载地址
boost有很多版本,一开始用的是boost_1_68_0 加 vs2010编译,后面在websocketpp编译的时候,存在异常。
最后换成boost_1_80_0,使用vs2017进行编译,QT版本为5.12.8
2.2 编译方法
步骤1:解压
解压后命令行进入boost_1_80_0文件夹内,执行:
.\bootstrap.bat
如果不指定编译器版本,就会用默认配置来编译。
如果默认配置是VS2019,但是想用VS2017编译,则命令行输入:
.\bootstrap.bat vc14
具体参数可以参见bootstrap.bat文件。
步骤2:文件路径
编译之后,QT开发需要的文件路径为:
- include: boost_1_80_0\boost
- lib :boost_1_80_0\stage\lib
步骤3:QT环境配置
将boost文件夹和lib文件夹放在qt工程根目录,和pro文件同级。
在qt的pro文件中增加
3 websocketpp
websocketpp是一个基于C11标准开发的websocket c++框架,源码地址为https://github.com/zaphoyd/websocketpp
从官网上下载源码,解压后将源码和pro文件同级。
在pro文件中添加头文件引用如下:
4 基于QT的websocketpp客户端开发
4.1 WebsocketClient.h文件
#ifndef WEBSOCKTHREAD_H
#define WEBSOCKTHREAD_H
#include <QObject>
#include <QThread>
#include <QDebug>
#include <QFile>
#include <QIODevice>
#include <QTime>
#include <QTimer>
#include <QString>
#include <QHostAddress>
#include <QDateTime>
#include <queue>
#include <websocketpp/client.hpp>
#include <websocketpp/config/asio_no_tls_client.hpp>
typedef websocketpp::client<websocketpp::config::asio_client> chat_client;
using websocketpp::lib::placeholders ::_1;
using websocketpp::lib::placeholders ::_2;
using websocketpp::lib ::bind;
typedef websocketpp::config::asio_client::message_type::ptr message_ptr;
class WebsockThread : public QThread
{
Q_OBJECT
public:
explicit WebsockThread(QString serverAddr,QObject *parent = nullptr);
~WebsockThread();
void startClient();
void initClient();
void sendData(QByteArray data);
void run();
void on_open(chat_client* client, websocketpp::connection_hdl hdl) ;
void on_close(chat_client* c, websocketpp::connection_hdl hdl);
void on_message(chat_client* client, websocketpp::connection_hdl hdl,chat_client::message_ptr msg_ptr);
void on_termination(chat_client* c, websocketpp::connection_hdl hdl);
chat_client m_client;
chat_client::connection_ptr m_con;
bool m_bConnect;
QString m_strAddr;
signals:
void signal_sendMsg( QString msg);
};
#endif // WEBSOCKTHREAD_H
4.2 WebsocketClient.cpp文件
#include "websockthread.h"
void WebsockThread::on_open(chat_client* client, websocketpp::connection_hdl hdl) {
chat_client::connection_ptr con = client->get_con_from_hdl(hdl);
if(con->get_ec().value()!=0){
m_bConnect = false;
}else{
m_bConnect = true;
}
}
void WebsockThread::on_message(chat_client* client, websocketpp::connection_hdl hdl,chat_client::message_ptr msg_ptr) {
chat_client::connection_ptr con = client->get_con_from_hdl(hdl);
if(msg_ptr->get_opcode() == websocketpp::frame::opcode::text){
QString msg = msg_ptr->get_payload().c_str();
emit signal_sendMsg(text);
}
}
void WebsockThread::on_close(chat_client* c, websocketpp::connection_hdl hdl) {
m_bConnect=false;
}
void WebsockThread::on_termination(chat_client* c, websocketpp::connection_hdl hdl)
{
}
WebsockThread::WebsockThread(QString serverAddr,QObject *parent )
:m_strAddr(serverAddr),QThread(parent)
{
m_bConnect = false;
}
/**
* @brief 线程入口
* @argc null
*/
void WebsockThread::run(){
initClient();
startClient();
}
void WebsockThread::initClient(){
m_client.clear_access_channels(websocketpp::log::alevel::frame_header);
m_client.clear_access_channels(websocketpp::log::alevel::frame_payload);
m_client.set_error_channels(websocketpp::log::elevel::none);
m_client.init_asio();
m_client.set_reuse_addr(true);
m_client.set_open_handler(bind(&WebsockThread::on_open, this,&m_client, ::_1));
m_client.set_message_handler(bind(&WebsockThread::on_message, this,&m_client, ::_1, ::_2));
m_client.set_close_handler(bind(&WebsockThread::on_close, this, &m_client, ::_1));
}
void WebsockThread::startClient(){
websocketpp::lib::error_code ec;
m_con = m_client.get_connection(m_strAddr.toStdString(), ec);
if (ec) {
qDebug()<< "could not create connection because: " ;
return ;
}
m_con->set_termination_handler(bind(&WebsockThread::on_termination, this, &m_client, ::_1));
m_client.connect(m_con);
m_client.run();
}
void WebsockThread::sendData(QByteArray data){
if(m_bConnect){
m_con->send(data.toStdString(),websocketpp::frame::opcode::BINARY);
}
}
WebsockThread::~WebsockThread(){
}