目次
1. WebSocket誕生の背景
初期の頃、多くの Web サイトはプッシュ テクノロジを実装するためにポーリング (ショート ポーリングとも呼ばれます) を使用していました。
ポーリングとは、ブラウザが定期的に HTTP リクエストをサーバーに送信し、サーバーが最新のデータをクライアントに返すことを意味します。
2. WebSocket の特徴:
1) TCP プロトコルに基づいて構築されているため、サーバー側の実装は比較的簡単です。
2) HTTPプロトコルとの互換性が良好です。デフォルトのポートも 80 と 443 です。
また、ハンドシェイク フェーズでは HTTP プロトコルが使用されるため、ハンドシェイク中にブロックするのは簡単ではなく、さまざまな HTTP プロキシ サーバーを通過できます。
3) データ形式は比較的軽量で、パフォーマンスのオーバーヘッドが低く、通信が効率的です。
4) テキストまたはバイナリ データを送信できます。
5) 送信元の制限はなく、クライアントは任意のサーバーと通信できます。
6) プロトコル識別子は ws (暗号化されている場合は wss)、サーバー アドレスは URL です。
ws://example.com:80/some/path のようになります。
3. WebSocket の概要
WebSocket は、単一の TCP 接続を介した全二重通信を可能にするネットワーク トランスポート プロトコルで、OSI モデルのアプリケーション層に位置します。
4. WebSocket の利点
1) 制御オーバーヘッドが少ない: 接続の作成後、サーバーとクライアントの間でデータが交換されるときに、プロトコル制御に使用されるパケット ヘッダーは比較的小さいです。
2) より強力なリアルタイム パフォーマンス: プロトコルは全二重であるため、サーバーはいつでもプロアクティブにデータをクライアントに送信できます。サーバーが応答する前にクライアントがリクエストを開始するのを待つ必要がある HTTP リクエストと比較すると、遅延は大幅に少なくなります。
3) 接続状態を維持する: HTTP とは異なり、WebSocket は最初に接続を作成する必要があるため、WebSocket はステートフル プロトコルとなり、その後の通信中に一部の状態情報を省略できます。
4) バイナリ サポートの向上: WebSocket はバイナリ フレームを定義しており、HTTP よりも簡単にバイナリ コンテンツを処理できます。
5) 拡張機能をサポートできる: WebSocket は拡張機能を定義し、ユーザーはプロトコルを拡張して、カスタマイズされたサブプロトコルを実装できます。
WebSocket には上記の利点があるため、インスタント メッセージング/IM、リアルタイム オーディオとビデオ、オンライン教育、ゲームなどの分野で広く使用されています。
5. QWebSocket 通信クライアント:
使用される主なインターフェース: (主な手順)
#include <QWebSocket>
QWebSocket* m_pDataRecvWS = new QWebSocket();
m_pDataRecvWS->open(QUrl("URL"));//形如:ws://example.com:80/some/path
//客户端发出请求后,服务器会处理发相应的信号:
//1、连接成功后
connected();
//2、连接失败
disconnected();
//3、收到数据
textMessageReceived();
//常用的函数--------------------------------------
//发送消息
sendTextMessage()
簡単な例:
//例子
QTimer m_timer = new QTimer();//重连计时器
if (m_pDataRecvWS == nullptr)
{
m_pDataRecvWS = new QWebSocket();
connect(m_pDataRecvWS, &QWebSocket::disconnected, this, &WebSocketClient::slotOnDisConnected, Qt::AutoConnection);
connect(m_pDataRecvWS, &QWebSocket::textMessageReceived, this, &WebSocketClient::slotOnTextReceived, Qt::AutoConnection);
connect(m_pDataRecvWS, &QWebSocket::connected, this, &WebSocketClient::slotOnConnected, Qt::AutoConnection);
connect(m_timer, QTimer::timeout, this, &WebSocketClient::slotReconnect, Qt::AutoConnection);
m_pDataRecvWS->open(QUrl(m_strURL));
}
//连接成功-关闭重连的计时器
void WebSocketClient::slotOnConnected()
{
m_bConnectStatus = true;
m_timer->stop();
}
//连接失败-启动计时器准备重连
void WebSocketClient::slotOnDisConnected()
{
m_bConnectStatus = false;
m_timer->start(3000);/*-<当连接失败时,触发重连计时器,设置计数周期为3秒 */
}
//重连
void WebSocketClient::slotReconnect()
{
m_pDataRecvWS->abort();
m_pDataRecvWS->open(QUrl(m_strURL));
}
//收到消息
void WebSocketClient::slotOnTextReceived(const QString& msg)
{
// todo
}
6. QWebSocket 通信 - サーバー:
使用される主なインターフェース: (主な手順)
//声明变量
QWebSocketServer *m_pWebSocketServer;
QList<QWebSocket *> m_clients;//保存连接的客户端
unsigned short mPort;//端口号
QString mServerName;//服务器名字
//1、创建服务器
m_pWebSocketServer = new QWebSocketServer(mServerName, QWebSocketServer::NonSecureMode, this);
//2、监听
m_pWebSocketServer->listen(QHostAddress::LocalHost, mPort);//端口号
//3、有新的连接,会发这个信号
connect(m_pWebSocketServer, &QWebSocketServer::newConnection, this, &WebSocketServer::onNewConnection);
//4、获得新的客户端nextPendingConnection
void WebSocketServer::onNewConnection()
{
auto pSocket = m_pWebSocketServer->nextPendingConnection();
pSocket->setParent(this);
connect(pSocket, &QWebSocket::textMessageReceived, this, &WebSocketServer::processMessage);
connect(pSocket, &QWebSocket::disconnected, this, &WebSocketServer::socketDisconnected);
m_clients << pSocket;//放进去客户端列表
}
//5、接收到信息
void WebSocketServer::processMessage(const QString &message)
{
QWebSocket *pSender = qobject_cast<QWebSocket *>(sender());
for (QWebSocket *pClient : qAsConst(m_clients))
{
emit processServerMessage(message);
if (pClient != pSender) //don't echo message back to sender
pClient->sendTextMessage(message);
}
}
//6、断开连接
void WebSocketServer::socketDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
QTextStream(stdout) << getIdentifier(pClient) << " disconnected!\n";
if (pClient)
{
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}