我是靠谱客的博主 碧蓝电灯胆,最近开发中收集的这篇文章主要介绍使用QWebSocketServer实现网络数据传输,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

学习记录贴,参考了许多文档,
部分内容参考自 https://www.jianshu.com/p/a9497de4cbff
内容参考自 https://blog.csdn.net/cqchengdan/article/details/97619665#commentBox
内容参考自 https://blog.csdn.net/cqchengdan/article/details/97619483
有问题可以相互请教,这里就是对今天学习内容的总结。

1.模式分类

QWebSocketServer具有安全模式和非安全模式两种类型。体现在初始化类型值的不同
QWebSocketServer::SecureMode 为安全模式。需要配置SSL安全证书,QWebSocketServer::NOSecureMode为非安全模式,直接进行明文传输。

2.非安全模式下QWebsocket实现

2.1 服务器端

1.初始化QWebSocketServer

void DataAnalysisClient::init()
{
    m_WebSocketServer = new QWebSocketServer("Server Name", QWebSocketServer::NoSecureMode, this);
}

2.实现服务器端接口

void DataAnalysisClient::onStartButtonClick()
{
    int i_port = 6000;
    m_WebSocketServer->listen(QHostAddress::Any, i_port);
    m_sendEdit->append(QString("服务启动!"));
}
void DataAnalysisClient::onStopButtonClick()
{
    m_WebSocketServer->close();
    for (int i=0;i<m_clients.size();i++)
    {
        m_clients.at(i)->close();
    }
    m_sendEdit->append(QString("服务停止!"));
}

void DataAnalysisClient::onSendButtonClick()
{
    QString msg = "服务端发送数据!";
    for (int i=0;i<m_clients.size();i++)
    {
        m_clients.at(i)->sendTextMessage(msg);
    }
}
void ACMSLIB::DataAnalysisClient::onNewConnection()
{
    // 读取到下一个等待连接的套接字,套接字需要显式删除
    pSocket = m_WebSocketServer->nextPendingConnection();
    connect(pSocket, SIGNAL(textMessageReceived(QString)), this, SLOT(processTextMessage(QString)));
    connect(pSocket, SIGNAL(disconnected()), this, SLOT(socketDisconnected()));
    QString item = pSocket->peerAddress().toString();
    QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");
    QString ip = m_WebSocketServer->serverAddress().toString();
    int port = m_WebSocketServer->serverPort();
    QString url = m_WebSocketServer->serverUrl().toString();
    m_sendEdit->append(QString("%1 + "" 新建连接:IP为%2").arg(time).arg(item));
    m_sendEdit->append(QString("IP:%1 + 端口号:%2 + url:%3").arg(ip).arg(port).arg(url));
    m_clients << pSocket;
}

//收到消息并显示
void DataAnalysisClient::processTextMessage(QString message)
{
    QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");
    QString item = pSocket->peerAddress().toString();
    m_recEdit->append(time + "" + item + "n" + message);
}

void DataAnalysisClient::socketDisconnected()
{
    QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz");
    QString item = pSocket->peerAddress().toString();
    m_recEdit->append(QString(time + "" + item + "n" + "失去连接:IP为%1").arg(item));
    m_recEdit->append("n");
}

2.2 客户端

1.初始化

    // 操作按钮
    connect(m_startBtn, SIGNAL(clicked(bool)), this, SLOT(connectToServer()));
    connect(m_closeBtn, SIGNAL(clicked(bool)), this, SLOT(stopClicked()));
    connect(m_sendBtn, SIGNAL(clicked(bool)), this, SLOT(onSendButtonClicked()));
    // 数据传输
    connect(&m_websocket, SIGNAL(connected()), this, SLOT(onconnected()));
    connect(&m_websocket, SIGNAL(disconnected()), this, SLOT(closeConnection()));
    connect(&m_websocket, SIGNAL(textMessageReceived(QString)), this, SLOT(onTextMessageReceived(QString)));

2.接口实现

void Widget::connectToServer()
{
    QString IP= "***.***.***.***";
    QString prot = "6000";
    QString path = QString("wss://%1:%2").arg(IP).arg(prot);
    QUrl url = QUrl(path);
    m_websocket.open(url);
    // 错误提示
    connect(&m_websocket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(readError(QAbstractSocket::SocketError)));
}

void Widget::onTextMessageReceived(const QString &message)
{
    m_recEdit->append("-----------------------------1");
    QString time = current_date_time->currentDateTime().toString("yyyy.MM.dd hh:mm:ss.zzz ddd");
    m_recEdit->append(time + "n" + message);
}

void Widget::closeConnection()
{
}

void Widget::stopClicked()
{
    m_websocket.close();
}

void Widget::onconnected()
{
    m_recEdit->append("连接成功");
}

void Widget::onSendButtonClicked()
{
    QString msg = "客户端发送数据";
    m_websocket.sendTextMessage(msg);
}

void Widget::onCleanButtonClicked()
{
}

void Widget::readError(QAbstractSocket::SocketError err)
{
    qDebug () << "连接Error!";
}

3.安全模式下QWebsocket实现

3.1 证书准备

QWebsocket安全模式需要对SSL进行验证,QT本身不支持SSL验证,手动下载openSSL

3.2 生成证书

下载安装好后,打开openssl.exe

3.2.1 生成密钥

genrsa -des3 -out server.key 2048

说明:生成rsa私钥,des3算法,2048位强度,server.key是秘钥文件名。
注意:生成私钥,需要提供一个至少4位的密码。

3.2.2 生成CSR(证书签名请求)

req -new -key server.key -out server.csr

说明:需要依次输入国家,地区,城市,组织,组织单位,Common Name和Email。其中Common Name,可以写自己的名字或者域名,如果要支持https,Common Name应该与域名保持一致,否则会引起浏览器警告。

Country Name (2 letter code) [AU]:CN
State or Province Name (full name) [Some-State]:Beijing
Locality Name (eg, city) []:Beijing
Organization Name (eg, company) [Internet Widgits Pty Ltd]:IT
Organizational Unit Name (eg, section) []:IT
Common Name (e.g. server FQDN or YOUR name) []:IT
Email Address []:123456789@qq.com

3.2.3 删除私钥中的密码

rsa -in server.key -out server_no.key

备注:必须操作,不删除的话,在不鉴定客户端证书的情况下也无法连接成功,
在3.2.1创建私钥的过程中,由于必须要指定一个密码。而这个密码会带来一个副作用,那就是在每次Apache启动Web服务器时,都会要求输入密码,这显然非常不方便。要删除私钥中的密码,操作如下:

3.2.4 生成自签名证书

x509 -req -days 365 -in server.csr -signkey server_no.key -out server.crt

由此得到了签名证书server.crt和私钥server_no.key

3.3 设计服务端

在原有使用非安全模式的WebsockeServer服务的基础上添加一些签名证书和验证
1.初始化QWebSocketServer

void DataAnalysisClient::init()
{
    m_WebSocketServer = new QWebSocketServer("Server Name", QWebSocketServer::SecureMode, this);
    //
    QFile certFile(":server.crt");
    QFile keyFile(":server.key");
    if(!certFile.open(QIODevice::ReadOnly)){
        qDebug() << "certfile open failed...";
    }
    if(!keyFile.open(QIODevice::ReadOnly)){
        qDebug() << "keyfile open failed...";
    }
    QSslCertificate cert(&certFile, QSsl::Pem);
    QSslKey key(&keyFile, QSsl::Rsa, QSsl::Pem);
    certFile.close();
    keyFile.close();
    QSslConfiguration conf = m_WebSocketServer->sslConfiguration();
    conf.setPeerVerifyMode(QSslSocket::VerifyNone);
    conf.setLocalCertificate(cert);
    conf.setPrivateKey(key);
    conf.setProtocol(QSsl::TlsV1SslV3);
    m_WebSocketServer->setSslConfiguration(conf);
}

3.4 设计客户端

void Widget::connectToServer()
{
    QString IP= "***.***.***.***";
    QString prot = "6000";
    QString path = QString("wss://%1:%2").arg(IP).arg(prot);
    QUrl url = QUrl(path);
    QSslConfiguration conf = m_websocket.sslConfiguration();
    conf.setPeerVerifyMode(QSslSocket::VerifyNone);
    conf.setProtocol(QSsl::TlsV1SslV3);
    m_websocket.setSslConfiguration(conf);
}

conf.setPeerVerifyMode(QSslSocket::VerifyNone);使用跳过证书验证的方式使用了SSL的安全传输,实现了数据加密功能。

3.5 使用证书验证

修改验证方式为QSslSocket::VerifyPeer,客户端初始化设置为
{
    QString IP= "***.***.***.***";
    QString prot = "6000";
    QString path = QString("wss://%1:%2").arg(IP).arg(prot);
    QUrl url = QUrl(path);
    QSslConfiguration conf = m_websocket.sslConfiguration();
    //conf.setPeerVerifyMode(QSslSocket::VerifyNone);
    conf.setPeerVerifyMode(QSslSocket::VerifyPeer);
    conf.setProtocol(QSsl::TlsV1SslV3);
    m_websocket.setSslConfiguration(conf);
    //解决自签名证书不受信赖问题,VerifyNone不需添加以下代码
    QList<QSslCertificate> certlist = QSslCertificate::fromPath("F:/myself/server.crt");
    QSslError error(QSslError::SelfSignedCertificate, certlist.at(0));
    QList<QSslError> expectedErrors;
    expectedErrors.append(error);
    m_websocket.ignoreSslErrors(expectedErrors);
}

此方法暂时不适用,websocket的报error提示SocketError::SslHandshakeFailedError错误,暂时不知道原因。

最后

以上就是碧蓝电灯胆为你收集整理的使用QWebSocketServer实现网络数据传输的全部内容,希望文章能够帮你解决使用QWebSocketServer实现网络数据传输所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(39)

评论列表共有 0 条评论

立即
投稿
返回
顶部