QT C++ WebSocket网络通信应用,多线程运行,服务端+客户端二合一

UI界面截图

QT C++ WebSocket网络通信应用,多线程运行,服务端+客户端二合一

说明

1、如有bug,敬请谅解,欢迎在评论区留言。
2、本程序使用多线程,即UI、服务端、客户端分别在不同的线程运行。
3、线程之间使用信号-槽方式进行交互。
4、初始设定:非安全模式通信,服务端监听所有地址。可修改监听端口。
5、源码下载链接在文章底部。

源码解析

界面

界面的主要操作:开启服务端/客户端线程、响应控件、通过自定义信号调用服务端/客户端的操作、接收服务端/客户端的消息信号、更新界面显示。代码参考源文件。

服务端

服务端的主要操作:开启监听、停止监听、客户端管理(接入/断开)、发送消息、接收消息、报错处理。


WSServer::WSServer(QObject *parent)
    : QObject(parent)
{
    WebSocketServer = new QWebSocketServer("LocalServer", QWebSocketServer::NonSecureMode, this);
    connect(WebSocketServer, &QWebSocketServer::newConnection, this, &WSServer::HasNewConnection);

    connect(WebSocketServer, SIGNAL(serverError(QWebSocketProtocol::CloseCode)),
            this             , SLOT(on_serverError(QWebSocketProtocol::CloseCode)));
}

void WSServer::Server_start(qint32 port)
{
    Server_Port = port;
    WebSocketServer->listen(QHostAddress(QHostAddress::Any), Server_Port);  //开启监听,任意地址,指定端口
}
 
void WSServer::Server_stop()
{
    foreach(QWebSocket* websocket, WSClients.values())
    {
        websocket->close(); //断开所有客户端连接
    }
    WebSocketServer->close();   //关闭服务
    WSClients.clear();  //清空哈希容器
}

void WSServer::remove_client(const QString ClientInfo)
{
    if(WSClients.contains(ClientInfo))
    {
        WSClients.value(ClientInfo)->close();	//断开客户端链接,相当于强制下线
        WSClients.remove(ClientInfo);   //移除指定客户端
    }
}
//服务端错误处理
void WSServer::on_serverError(QWebSocketProtocol::CloseCode error_code)
{
    emit occur_error("error message:server error," + WebSocketServer->errorString()
                     + "\nerror code:" + QString::number(error_code));
}
//客户端连接错误处理
void WSServer::on_clientError(QAbstractSocket::SocketError error_code)
{
    QWebSocket* error_client = qobject_cast<QWebSocket*>(sender());
    emit occur_error("error message:client error," + error_client->errorString()
                     + "\nerror code:" + QString::number(error_code));
}
 //有新的客户端接入,处理客户端的断开连接信号、错误信号、消息信号,将客户端加入哈希容器管理
void WSServer::HasNewConnection()
{
    QWebSocket* NewClient = WebSocketServer->nextPendingConnection();
    connect(NewClient, &QWebSocket::disconnected, this, &WSServer::on_ClientDisconnected);
    connect(NewClient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(on_clientError(QAbstractSocket::SocketError)));
    // 客户端发来消息时,既会触发textFrame,也会触发textMessage,此处只写text
    connect(NewClient, &QWebSocket::textMessageReceived, this, &WSServer::on_textMessageReceived);

    QString NewClientInfo = QString("%1-%2").arg(NewClient->peerAddress().toString()).arg(NewClient->peerPort());

    WSClients.insert(NewClientInfo, NewClient);

    emit NewClient_conncted(NewClientInfo);
}
 //客户端断开连接
void WSServer::on_ClientDisconnected()
{
    QWebSocket *client = qobject_cast<QWebSocket *>(sender());
    if(!client)
    {
        return;
    }
    QString ClientInfo = QString("%1-%2").arg(client->peerAddress().toString()).arg(client->peerPort());
    emit Client_disconncted(ClientInfo);    //发出信号给到UI线程

    WSClients.remove(ClientInfo);   //移除客户端
}
 //接收客户端消息
void WSServer::on_textMessageReceived(const QString &message)
{
    QWebSocket* client = qobject_cast<QWebSocket *>(sender());
    if(!client)
    {
        return;
    }
    QString ClientInfo = QString("%1-%2").arg(client->peerAddress().toString()).arg(client->peerPort());
    emit NewTextMessage(ClientInfo, message);   //发出信号给到UI线程
}

//服务器发消息,UI界面可选择发至所有客户端或指定客户端
void WSServer::Server_sendmsg(QString ClientInfo, QString message, bool isAllClients)
{
   if(!isAllClients)
   {
       if(WSClients.contains(ClientInfo))
       {
           WSClients.value(ClientInfo)->sendTextMessage(message);
       }
   }
   else
   {
       foreach(QWebSocket* websocket, WSClients.values())
       {
           websocket->sendTextMessage(message);
       }
   }
}

客户端

客户端的主要操作:连接服务端、断开连接、发送消息、接收消息、报错处理。


WSClient::WSClient(QObject *parent)
    : QObject(parent)
{
    WSClientObj = new QWebSocket;   //构造函数未设置参数和指定父对象
    WSClientObj->setParent(this);   //这里必须设置父对象,否则多线程运行报错
    //客户端需要处理的信号:连接成功、断开连接、发生错误、收到消息
    connect(WSClientObj, &QWebSocket::connected, this, &WSClient::on_connected);
    connect(WSClientObj, &QWebSocket::disconnected, this, &WSClient::on_disconnected);
    connect(WSClientObj, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(on_error(QAbstractSocket::SocketError)));
    connect(WSClientObj, &QWebSocket::textMessageReceived, this, &WSClient::on_textMessageReceived);
}

//连接服务端
void WSClient::ConnectTo(const QString url)
{
    WSClientObj->open(QUrl(url));
}
//断开连接
void WSClient::Disconnect()
{
    WSClientObj->close();
}
 //发消息,字符串
void WSClient::sendTextMessage(const QString message)
{
    WSClientObj->sendTextMessage(message);
}
 //发消息,二进制
void WSClient::sendBinaryMessage(const QByteArray data)
{
    WSClientObj->sendBinaryMessage(data);
}
 //连接成功,通知UI
void WSClient::on_connected()
{
    emit connection_state("success connected", true);   //true/false用于UI判断更新控件可用状态
}
 //断开连接,通知UI
void WSClient::on_disconnected()
{
    emit connection_state("success disconnected", false);
}
 //报错,通知UI
void WSClient::on_error(QAbstractSocket::SocketError error)
{
    emit occur_error("error message:" + WSClientObj->errorString() + "\nerror code:" + QString::number(error));
}
 //接收消息,通知UI
void WSClient::on_textMessageReceived(const QString& message)
{
    emit NewTextMessage(message);
}

源码地址

WebSocketApplication-V1.0

上一篇:Template


下一篇:Qt编码问题解决实践(中文乱码,UTF-8与GBK转换,QString转QByteArray)