(只是作为个人纪录,如果你要使用的话在 Qt 示例里搜 websocket 看官方 Demo 就行了,代码量不多)
(参见Qt文档说明)WebSockets 是一种通过单个 TCP 连接提供全双工通信信道的 web 技术。2011年,IETF 将 WebSocket 协议标准化为 RFC 6455 。Qt 提供的 QWebSocket 既可以用于客户端应用程序,也可以用于服务端应用程序,接口大部分和 QTcpSocket 一致。
QWebSocket 当前不支持 WebSocket 扩展和 WebSocket 子协议,仅支持 WebSocket 协议的版本13 (如 RFC 6455 中所述)。
(完整代码链接,包含 Qt Server/Client 和 HTML Client:https://github.com/gongjianbo/MyTestCode/tree/master/Qt/QtWebSocketDemo)
要使用 Qt 的 WebSocket 模块,先在 pro 文件中加上 websockets:
QT += websockets
这是我 Demo 界面:
对于服务端,需要用到 QWebSocketServer 和 QWebSocket 两个类。创建 Server 对象后,使用 listen 函数监听端口,新的连接到来时,触发 newConnection 信号,这时候才槽函数种使用 nextPendingConnection 函数获取到这个 Socket 连接。
主要实现代码:
WebSocketServer::WebSocketServer(QWidget *parent) :
QWidget(parent),
ui(new Ui::WebSocketServer)
{
ui->setupUi(this);
//构造:QWebSocketServer(const QString& serverName,QWebSocketServer::SslMode secureMode,QObject *parent=nullptr)
//使用给定的serverName构造一个新的QWebSocketServer。
//该服务器名称将在HTTP握手阶段被用来识别服务器。它可以为空,此时不会将服务器名称发送给客户端。
//SslMode指示服务器是通过wss(SecureMode)还是ws(NonSecureMode)运行
//QWebSocketServer::SecureMode服务器以安全模式运行(通过wss)
//QWebSocketServer::NonSecureMode服务器以非安全模式运行(通过ws)
server=new QWebSocketServer("Server",QWebSocketServer::NonSecureMode,this);
//服务器监听
ui->btnSend->setEnabled(false);
connect(ui->btnListen,&QPushButton::clicked,[this](){
if(ui->btnListen->text()!="Listen"){
ui->btnSend->setEnabled(false);
ui->btnListen->setText("Listen");
clearClient();
server->close();
}else{
QHostAddress address;
if(ui->editAddress->text()=="Any"){
address=QHostAddress::Any;
}else{
address=QHostAddress(ui->editAddress->text());
}
//判断是否连接上
if(server->listen(address,ui->editPort->text().toUInt())){
ui->btnSend->setEnabled(true);
ui->btnListen->setText("Dislisten");
}
}
});
//新的连接进来
connect(server,&QWebSocketServer::newConnection,this,&WebSocketServer::onNewConnection);
//发送消息给客户端
connect(ui->btnSend,&QPushButton::clicked,[this](){
if(!ui->editSend->toPlainText().isEmpty())
emit sendMessage(ui->editSend->toPlainText());
});
}
WebSocketServer::~WebSocketServer()
{
clearClient();
server->close();
delete ui;
}
void WebSocketServer::clearClient()
{
for(int i=clientList.count()-1;i>=0;i--)
{
//qDebug()<disconnect();
clientList.at(i)->close();
}
qDeleteAll(clientList);
clientList.clear();
}
void WebSocketServer::onNewConnection()
{
QWebSocket *socket=server->nextPendingConnection();
if(!socket)
return;
clientList.push_back(socket);
ui->editRecv->append(QString("[New Connect] Address:%1 Port:%2")
.arg(socket->peerAddress().toString())
.arg(socket->peerPort()));
//收到消息
connect(socket,&QWebSocket::textMessageReceived,[this](const QString &msg){
ui->editRecv->append(msg);
});
//发送消息
connect(this,&WebSocketServer::sendMessage,socket,&QWebSocket::sendTextMessage);
//断开连接,释放
connect(socket,&QWebSocket::disconnected,[this,socket](){
clientList.removeAll(socket);
socket->deleteLater();
});
}
对于客户端,好像没有指定 bind 自己端口的接口,只能指定服务端的 Url。通过 open 函数连接服务端的 Url ,使用 close 关闭连接。数据到来的时候有 textMessageReceived 和 binaryMessageReceived 等信号触发,也可以调用 sendTextMessage 或 sendBinaryMessage 发送数据。
主要实现代码:
WebSocketClient::WebSocketClient(QWidget *parent) :
QWidget(parent),
ui(new Ui::WebSocketClient)
{
ui->setupUi(this);
//构造:QWebSocket(const QString &origin = QString(), QWebSocketProtocol::Version version = QWebSocketProtocol::VersionLatest, QObject *parent = nullptr)
//使用给定的源,要使用的协议版本和parent创建一个新的QWebSocket 。
client=new QWebSocket;
client->setParent(this);
//连接服务端
connect(ui->btnOpen,&QPushButton::clicked,[this](){
if(ui->btnOpen->text()!="Open"){
client->close();
}else{
client->open(QUrl(ui->editUrl->text()));
}
});
//连接结果
ui->btnSend->setEnabled(false);
connect(client,&QWebSocket::connected,[this](){
ui->btnSend->setEnabled(true);
ui->btnOpen->setText("Close");
ui->footLabel->setText(QString("Address:%1 Port:%2")
.arg(client->localAddress().toString())
.arg(client->localPort()));
qDebug()<<"connected";
});
connect(client,&QWebSocket::disconnected,[this](){
ui->btnSend->setEnabled(false);
ui->btnOpen->setText("Open");
qDebug()<<"disconnected";
});
//发送数据
connect(ui->btnSend,&QPushButton::clicked,[this](){
if(!ui->editSend->toPlainText().isEmpty())
client->sendTextMessage(ui->editSend->toPlainText());
});
//接收数据
connect(client,&QWebSocket::textMessageReceived,[this](const QString &msg){
ui->editRecv->append(msg);
});
}
WebSocketClient::~WebSocketClient()
{
//结束的时候没关会异常
client->close();
delete ui;
}
网页 WebSocket 客户端的简单 Demo:
Qt WebSocket Demo
Recv:
Send:
Windows 命令行(管理员权限)输入 netsh winsock reset,等出现提示后重启电脑。
参考:https://blog.csdn.net/zxl_1996/article/details/86333945
Netsh winsock reset是一个命令提示程序,用于将winsock目录重置为默认设置或清除状态。如有时候上不了网或者网络出现问题经常用到它,简单地理解就是:重置程序通过操作系统链接网络的入口点。虽然使用此命令可以恢复网络连接,也应谨慎使用,因为可能需要重新安装LSPLSP: layered service privider 分层服务提供商。LSP是TCP/IP等协议的接口。
参考:https://baijiahao.baidu.com/s?id=1621092219410327325&wfr=spider&for=pc
Qt 文档:https://doc.qt.io/qt-5/qwebsocket.html
HTML Websocket:https://www.runoob.com/html/html5-websocket.html