UI界面截图
说明
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);
}