2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
पूर्वपर्यावरणं शिक्षणम्
QT TCP बहु-धागा संजाल संचार-CSDN Blog
WebSocket इति संजालप्रौद्योगिकी अस्ति या एकस्मिन् TCP संयोजने पूर्ण-द्वैध-सञ्चार-मार्गं प्रदाति । २०११ तमे वर्षे IETF इत्यनेन WebSocket प्रोटोकॉल इत्यस्य मानकीकरणं RFC6455 इति कृतम्, QWebSocket इत्यस्य उपयोगः क्लायन्ट् अनुप्रयोगेषु सर्वर अनुप्रयोगेषु च कर्तुं शक्यते ।
एतत् ब्राउजर्-सर्वरयोः मध्ये पूर्ण-द्वैध-सञ्चारं कार्यान्वयति, येन सर्वरः सक्रियरूपेण क्लायन्ट्-इत्यस्मै सूचनां प्रेषयितुं शक्नोति ।
मुख्यविशेषता : १.
HTTP इत्यस्य विपरीतम्, WebSocket इत्यनेन सर्वरः सक्रियरूपेण क्लायन्ट् प्रति दत्तांशं प्रेषयितुं शक्नोति, क्लायन्ट् इत्यस्य अनुरोधस्य आरम्भस्य आवश्यकतां विना ।
TCP प्रोटोकॉल इत्यत्र निर्मितं Ws (WebSocket) प्रोटोकॉलद्वारा एकस्मिन् पोर्ट् मध्ये सर्वरस्य क्लायन्ट् च मध्ये पूर्ण-द्वयात्मकसञ्चारः क्रियते ।
पाठेन अथवा द्विचक्रीयरूपेण दत्तांशसञ्चारं समर्थयति ।
प्रोटोकॉल एकस्मिन् TCP संयोजने निर्मितः अस्ति, सर्वरस्य क्लायन्ट् च केवलं एकं संयोजनं निर्मातुं आवश्यकं भवति, संयोजनं च बन्दं न भविष्यति ।
जावास्क्रिप्ट्, जावा, सी#, पायथन् इत्यादिषु बहुषु प्रोग्रामिंगभाषासु क्लायन्ट्-साइड् तथा सर्वर-साइड् पुस्तकालयानाम् समर्थनं करोति ।
सामान्यानि अनुप्रयोगपरिदृश्यानि : १.
गपशप-कक्षः : न्यून-विलम्बता-वास्तविक-समय-वार्तालापस्य समर्थनं करोति ।
ऑनलाइन-क्रीडा: एकं समन्वयन-इञ्जिनं यस्य कृते क्रीडा-स्थितेः वास्तविक-समय-समन्वयनस्य आवश्यकता भवति ।
स्टॉक उद्धरणम् : उद्धरणसॉफ्टवेयरं यस्य ग्राहकं प्रति वास्तविकसमयस्य उद्धरणं धक्कायितुं आवश्यकम् अस्ति।
वीडियो सम्मेलनम् : स्वरस्य विडियोस्य च न्यूनविलम्बतायां वास्तविकसमयसञ्चारः आवश्यकः अस्ति ।
वास्तविकसमयसहकारसम्पादनम् : उदाहरणार्थं, ऑनलाइनकोड् सम्पादकस्य वास्तविकसमयसमन्वयनस्य आवश्यकता भवति ।
QWebSocket इति Qt द्वारा प्रदत्तं WebSocket फंक्शन् लाइब्रेरी अस्ति । इदं Qt संजालमॉड्यूले निर्मितं भवति तथा च RFC6455 मानके WebSocket प्रोटोकॉलं कार्यान्वितं करोति । भवद्भिः Qmake सञ्चिकायां QT+=websockets योजयितव्यम्
QWebSocket केवलं Text/Binary सन्देशस्वरूपं समर्थयति अन्येषां विस्तारितानां प्रारूपाणां समर्थनं न करोति । यदि अन्ये कस्टम् प्रोटोकॉल योजयितुं आवश्यकाः सन्ति तर्हि विकासकाः अनुप्रयोगस्तरस्य स्वयमेव तत् सम्पादयितुं आवश्यकाः सन्ति ।
एतत् मानक http/https पोर्ट् 80/443 इत्यस्य उपयोगेन websocket सेवासु प्रवेशं समर्थयति, अपि च wss (encrypted websocket) प्रोटोकॉल इत्यस्य समर्थनं करोति । अतः विद्यमानजालसर्वरैः सह सहजतया अन्तरक्रियां कर्तुं शक्नोति ।
यतः एतत् QT CP सॉकेट् कार्यान्वयनम् आधारितम् अस्ति, अतः एतत् सर्वाणि Qt संजालकार्यं पूर्णतया समर्थयति, यथा प्रॉक्सी सेटिंग्स्, SSL विन्यासः इत्यादयः । केषाञ्चन निम्नस्तरीय C अन्तरफलकानां अपेक्षया एतस्य उपयोगः सुकरः अस्ति ।
एतत् सक्रिय-निष्क्रिय-संयोजनविधानयोः समर्थनं करोति । सक्रियसंयोजनानि connectToHost() इत्यस्य माध्यमेन भवन्ति, निष्क्रियसंयोजनानि च श्रवणपोर्ट् accept() इत्यस्य माध्यमेन स्वीक्रियन्ते । उभयविधौ अतीव सुलभौ स्तः ।
QT GUI अनुप्रयोगानाम् कृते बहु-थ्रेडेड् प्रोग्रामिंग् इत्यस्य जटिलतां परिहरन् सन्देश-स्वागतं, अन्तरफलक-अद्यतनं च सुलभतया कर्तुं शक्यते । यथा, केवलं textMessageReceived() मध्ये प्रत्यक्षतया अन्तरफलकं अद्यतनं कुर्वन्तु ।
QT5.10 इत्यस्य अनन्तरं, अतुल्यकालिक I/O समर्थितम् अस्ति, तथा च पूर्वस्य तुलने कार्यक्षमतायाः किञ्चित् उन्नतिः भवति । संजालविस्तारस्य समर्थनम् अपि श्रेष्ठम् अस्ति ।
-
- origin()
- 即 websocket=new QWebSocket("C1我是客户端",QWebSocketProtocol::VersionLatest,this);
- websocket->origin() -》 C1我是客户端
-
- void connectToHost(const QUrl &url) - 用于连接到指定主机的websocket服务,这个函数是异步的。
- void close() - 关闭与服务器的连接。
- void textMessageReceived(const QString &message) - 收到文本消息时触发的信号,其参数就是收到的文本消息内容。
- void binaryMessageReceived(const QByteArray &message) - 收到二进制消息时触发的信号,参数是原始二进制数据。
- void error(QAbstractSocket::SocketError socketError) - 发生错误时触发的信号,参数是错误类型。
- void stateChanged(QAbstractSocket::SocketState state) - 连接状态变化时触发,可以得知连接是否建立等。
- void textMessageSent(qint64 numBytes) - 发送文本消息完成后触发,numBytes是字节数。
- void bytesWritten(qint64 bytes) - 消息发送过程中的写入回调, bytes是一个部分发送出去的字节数。
- void abort() - 主动断开连接。
- bool waitForConnected(int msec = 30000) - 阻塞等待连接建立成功。
- QString hostName() - 获取当前连接的主机名,常用于判断连接是否成功。
- quint16 port() - 获取主机端口号。
- bool openMode() - 判断当前是否为主动连接还是被动接受模式。
- void writeTextMessage(const QString &text) - 发送文本消息,相比textMessage等更直观。
- void writeMessage(const QByteArray &data) - 发送二进制数据。
- qint64 bytesAvailable() - 查看接收缓存中可读取字节数。
- qint64 readBufferSize() - 设置双向数据接收缓存大小。
- void pauseIncomingPayload() - 暂停接收消息流。
- void resumeIncomingPayload() - 恢复接收。
- bool isValid() - 检查连接是否有效。
- 另外,作为QT套接字,它还支持一些通用功能:
- void setProxy() - 设置代理。
- void encrypt() - 设置SSL安全连接。
- void flush() - 强制输出缓存写出。
- bool waitForBytesWritten() - 等待数据发送完毕。
-
- void QWebSocket::sendTextMessage(const QString &message) 用于发送文本消息
- 使用这个函数发送文本消息主要有以下几点需要注意的地方:
- 1发送文本消息前请确保WebSocket连接已经建立。可以通过ReadyState判断连接状态。
- 2发送的消息内容必须是纯文本,不支持转义编码等更多格式。
- 3一条消息发送完毕后,会触发textMessageSent()信号通知。
- 4可以通过waitForBytesWritten()等待数据完全发送出去。
- 5发送数据顺序可能与收到响应顺序不一致,需要应用层自己处理序号等。
- 6若消息较大,建议使用write或send到套接字后flush,而不是sendTextMessage。
- 7跨平台考虑,消息内容编码最好使用QString而不是QByteArray。
- 8使用该函数发送的文本消息类型,服务端一般对应文本框接受。
- 9可以绑定消息发送断开连接的异常处理等。
sendTextMessage तथा writeTextMessage इत्येतयोः कार्ययोः उपयोगः पाठसन्देशप्रेषणार्थं कर्तुं शक्यते, परन्तु तेषु केचन भेदाः सन्ति:
sendTextMessage QWebSocket इत्यस्य सदस्यकार्यस्य अस्ति;
writeTextMessage QAbstractSocket इत्यस्य सदस्यकार्यं भवति, QWebSocket च QAbstractSocket इत्यस्मात् उत्तराधिकारं प्राप्नोति ।
आन्तरिकरूपेण sendTextMessage प्रथमं सन्देशं QByteArray मध्ये परिवर्तयिष्यति, ततः write function इत्यस्य माध्यमेन प्रेषयिष्यति, यत् एकं अधिकं परिवर्तनम् अस्ति;
writeTextMessage प्रत्यक्षतया QString लिखति यत् प्रेषयितुं आवश्यकं भवति, यत् किञ्चित् अधिकं कार्यक्षमम् अस्ति ।
sendTextMessage एकं समन्वयात्मकं कार्यं भवति तथा च प्रेषणस्य समाप्तेः अनन्तरं पुनः आगमिष्यति;
writeTextMessage अतुल्यकालिक-आह्वानस्य समर्थनं करोति, तथा च Lambda-माध्यमेन callback-कार्यं निर्दिष्टुं शक्यते ।
sendTextMessage त्रुटिसूचना न प्रत्यागमिष्यति तथा च केवलं संकेतदोषाणां माध्यमेन एव नियन्त्रयितुं शक्यते;
writeTextMessage प्रेषणस्थितिं निर्धारयितुं प्रत्यागतं त्रुटिसङ्केतं प्राप्तुं शक्नोति ।
sendTextMessage WebSocket इत्यत्र केन्द्रितं भवति तथा च WebSocket API आह्वयितुं उपयुक्तम् अस्ति;
writeTextMessage अधिकं सामान्यं भवति तथा च अन्यैः QAbstractSocket उपवर्गैः सह उपयोक्तुं शक्यते ।
सामान्यतया : १.
sendTextMessage उपयोगाय सरलतरं, सुसमाहितं, मूलभूतप्रयोगाय उपयुक्तं च अस्ति;
writeTextMessage किञ्चित् अधिकं कार्यक्षमम् अस्ति, अतुल्यकालिकं त्रुटिनियन्त्रणम् इत्यादीनां अधिकविशेषतानां समर्थनं करोति, उच्चप्रदर्शनस्य अथवा नियन्त्रणस्य आवश्यकतायुक्तानां परिदृश्यानां कृते उपयुक्तः अस्ति
क्लायन्ट्-क्लायन्ट्-योः मध्ये निजीसञ्चारः, क्लायन्ट्-सर्वर्-योः मध्ये संचारः ।
प्रक्रिया: QWebServer रचयन्तु, नूतनं संयोजनं कॉलबैकं बन्धयन्तु, विच्छेदनं च शृणुत।
नूतनसंयोजनकॉलबैक्: यदा संग्रहे नूतनं संयोजनं योजितं भवति तदा अफलाइन तथा रिसीव तथा त्रुटिकॉलबैक् नूतनसंयोजनसॉकेट् मध्ये बाध्यते।
सन्देशं प्रेषयन्तु बटनम्: सर्वाणि एकं च वर्गीकृत्य, सेट् संग्रहं भ्रमन्तु, sendTextMesg इत्यस्य उपयोगेन प्रेषयन्तु च
- #include "widget.h"
- #include "ui_widget.h"
- //这个是服务器端
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
- /*
- * mode
- NonSecureMode: 不安全模式,即不使用SSL/TLS进行通信。这是默认值。
- SecureMode: 安全模式,以SSL/TLS安全通信。客户端和服务端之间的连接将使用SSL握手建立安全通道。
- AutomaticallyAcceptServerCertificates: 自动接受服务器证书。在SecureMode下,客户端无法验证证书时,自动接受服务器发来的证书以建立连接。
- VerifyNone: 不验证证书。以SecureMode运行,但不会验证客户端和服务端使用的证书。
- */
- webServer = new QWebSocketServer("testWebServer",QWebSocketServer::NonSecureMode,this);
- QObject::connect(webServer,&QWebSocketServer::newConnection,this,&Widget::MyselfNewConnectCallBackSlot);
-
- webServer->listen(QHostAddress::Any,8888);
- }
- void Widget::MyselfNewConnectCallBackSlot(){//新连接回调
-
- if(webServer->hasPendingConnections()){
- QWebSocket* websocket=webServer->nextPendingConnection();
- ui->msgtext->append(websocket->origin()+"客户端已连接到服务器");
- sockets<<websocket;
-
- QListWidgetItem * item =new QListWidgetItem;
- item->setText(websocket->origin());
- ui->clinetls->addItem(item);
-
-
- //绑定离开
- QObject::connect(websocket,&QWebSocket::disconnected,this,[websocket,this](){
- ui->msgtext->append(websocket->origin()+"客户端断开服务器连接");
- sockets.removeOne(websocket);
- for(int i=0;i<ui->clinetls->count();i++)
- {
- QListWidgetItem *item=ui->clinetls->item(i);
-
- if(item->text()==websocket->origin())
- {
- ui->clinetls->removeItemWidget(item);
- delete item;
- break;
- }
- }
-
- websocket->deleteLater();
-
- });
-
-
- //接受消息回调
- QObject::connect(websocket,&QWebSocket::textMessageReceived,this,[this](const QString &msg){
- QJsonDocument doc =QJsonDocument::fromJson(msg.toLatin1().data());
- if(doc.isNull()){
- QWebSocket* websocket =qobject_cast<QWebSocket*>(sender());//sender 触发信号的源头
- ui->msgtext->append("收到客户端消息["+websocket->origin()+"]--->"+msg);
-
- }else{
- //客户端之间的单发消息
- QJsonObject obj=doc.object();
- QString dst=doc["dst"].toString();
- for (auto& socket : sockets) {
- if(dst == socket->origin()){
- socket->sendTextMessage(msg);
- }
- }
- }
- });
-
-
- QObject::connect(websocket,QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error),
- this,[this](QAbstractSocket::SocketError error){
- QWebSocket* web =qobject_cast<QWebSocket*>(sender());
- ui->msgtext->append(web->origin()+"出错"+web->errorString());
- });
- }
-
-
-
- }
- Widget::~Widget()
- {
- delete ui;
- for(auto socket:sockets)
- {
- socket->close();
- }
-
- webServer->close();
- }
-
-
- void Widget::on_sendpb_clicked()
- {
- QString send =ui->sendtext->toPlainText().trimmed();
- if(send.isEmpty())return;
- if(ui->allradio->isChecked()){
- //群发
- if(sockets.size()==0)return;
- foreach(auto &socket,sockets){
- socket->sendTextMessage(send);
- }
- ui->msgtext->append("服务器给所有连接发送:"+send);
- }else{ //私发 取客户端名称 找 发
- if(!ui->clinetls->currentItem())return;
- QString cname =ui->clinetls->currentItem()->text();
-
- for(auto &socket:sockets)
- {
- if(socket->origin()==cname)
- {
- socket->sendTextMessage(send);
- ui->msgtext->append("服务端给["+socket->origin()+"]发送--->"+send);
-
- break;
- }
- }
- }
-
-
- ui->sendtext->clear();
- }
websocket संयोजनप्रक्रियाम् कार्यान्वितुं बटनं नुदन्तु: websocket रचयन्तु, विविधानि callbacks बाइण्ड् कुर्वन्तु, open(url) इत्यस्य माध्यमेन च संयोजयन्तु
सन्देशं प्रेषयतु बटनम् : निजीसन्देशान् सर्वरसन्देशान् च वर्गीकृत्य, निजीसन्देशान् json प्रारूपेण समाहितं कुर्वन्तु, ततः प्रेषयन्तु ।
- #include "widget.h"
- #include "ui_widget.h"
- #include<QMessageBox>
- Widget::Widget(QWidget *parent)
- : QWidget(parent)
- , ui(new Ui::Widget)
- {
- ui->setupUi(this);
-
- websocket=nullptr;
-
- }
-
- Widget::~Widget()
- {
- delete ui;
- }
-
-
- void Widget::on_sendpb_clicked()
- {
- if(!websocket && !websocket->isValid())
- return;
-
- QString send=ui->sendtext->toPlainText().trimmed();
- if(send.isEmpty())return;
-
-
- QString cname =ui->onetextmsg->text().trimmed();
- if(cname.isEmpty()){ //发给服务器
- websocket->sendTextMessage(send);
- ui->msgtext->append("发送消息:"+send);
- }else{
- //私聊发
- QJsonObject obj;
- obj["src"]=websocket->origin();
- obj["dst"]=cname;
- obj["msg"]=send;
- //将一个QJsonObject类型的obj转换成JSON字符串。 Compact参数指定格式化方式为紧凑格式(每个元素占一行)。紧凑格式输出结构清晰,容量小,适合传输和存储。
- QString str(QJsonDocument(obj).toJson(QJsonDocument::Compact));
- websocket->sendTextMessage(str);
- }
- ui->sendtext->clear();
-
-
- }
-
- void Widget::on_connect_clicked()
- {
-
- if(websocket == nullptr){
- if(ui->server_addr->text().trimmed().isEmpty()){
- QMessageBox::critical(this,"错误","服务器名称不能为空,请重新检查!",QMessageBox::Yes);
- return;
- }
- //用于移除字符串开头和结尾处的空白字符。 输入: " test " trimmed()后的结果: "test" VersionLatest使用最新的websocket协议版本。
- websocket=new QWebSocket(ui->client_name->text().trimmed(),QWebSocketProtocol::VersionLatest,this);
-
- //连接回调
- QObject::connect(websocket,&QWebSocket::connected,this,[this](){
- ui->msgtext->append("已经连接上"+websocket->peerAddress().toString());
- isConnecting=true;
- ui->connect->setText("断开服务器");
- });
- //断开回调
- QObject::connect(websocket,&QWebSocket::disconnected,this,[this](){
- ui->msgtext->append("已"+websocket->peerAddress().toString()+"断开连接");
- isConnecting=false;
- ui->connect->setText("连接服务器");
- });
-
- QObject::connect(websocket,QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error)
- ,this,[this](QAbstractSocket::SocketError){
- ui->msgtext->append(websocket->origin()+"出错"+websocket->errorString());
-
- });
-
-
- //接受消息回调 网上知名bug 当你连续发送 A:A*100 B:200时 接收方:A*100200 通过消息队列方式发送即可
- connect(websocket,&QWebSocket::textMessageReceived
- ,this,[this](const QString &msg){
- QJsonDocument jsd=QJsonDocument::fromJson(msg.toUtf8().data());
-
- if(jsd.isNull()) //解析失败 即没有 c1:c2 客户端与客户端私聊
- {
- ui->msgtext->append("收到消息:"+msg);
- }
- else
- {
- QJsonObject jsobj=jsd.object();
- ui->msgtext->append("收到来自"+jsobj["src"].toString()+"的消息:"+jsobj["msg"].toString());
- }
- },Qt::QueuedConnection);
-
-
-
- }
-
- if(isConnecting){ //连接是成功的
- websocket->close();
- websocket->deleteLater();
- websocket=nullptr;
-
- } else
- {
- websocket->open(QUrl(ui->server_addr->text().trimmed()));
- }
- }
सामान्यतया, QWebSocket, QT संजालपुस्तकालयस्य घटकरूपेण, WebSocket क्लायन्ट्-सर्वर्-विकासाय सुविधाजनक-एपिआइ-समूहं प्रदाति ।
अस्य मुख्याः लाभाः सन्ति : १.
पूर्णतया वस्तु-उन्मुखं डिजाइनं, एपिआइ सरलं, उपयोगाय च सुलभम् अस्ति ।
अन्यैः QT संजालघटकैः सह अत्यन्तं एकीकृतम्, यथा SSL/proxy समर्थनम् ।
इवेण्ट्-ड्राइवन् मॉडल् इत्यस्य उपयोगेन विकासकानां बहु-थ्रेडिंग् इत्यादिभिः अन्तर्निहितविवरणैः सह व्यवहारस्य आवश्यकता नास्ति ।
Qt GUI अनुप्रयोगैः सह स्वाभाविकतया एकीकृताः, सन्देशाः, अन्तरफलक-अद्यतनं च प्रत्यक्षतया आह्वयितुं शक्यन्ते ।
WebSocket मूलभूतविनिर्देशानां सम्पूर्णं कार्यान्वयनम् प्रदाति, यस्य उपयोगः विकासस्य सुविधायै पेटीतः बहिः कर्तुं शक्यते ।
कार्यक्षमता अपि उत्तमम् अस्ति, विशेषतः यतः QT5.10 अतुल्यकालिक I/O आह्वानं समर्थयति ।
सन्दर्भार्थं समृद्धानि उदाहरणानि मुक्तस्रोतपरियोजनानि च उपलभ्यन्ते, प्रवेशबाधा च न्यूना अस्ति ।
केचन बिन्दवः द्रष्टव्याः सन्ति- १.
केचन विस्तारिताः websocket protocol प्रारूपाः समर्थिताः न सन्ति, तेषां कार्यान्वयनम् आवश्यकम् अस्ति ।
सन्देशप्रेषणस्य ग्रहणस्य च क्रममेलनं स्वयमेव नियन्त्रितव्यम् ।
सञ्चिका तथा स्ट्रीमिंग् बृहत् आँकडा संचरण समर्थनं पर्याप्तं मैत्रीपूर्णं सरलं च नास्ति ।
प्रयुक्ताः अन्तर्निहिताः स्मार्ट-सूचकाः स्मृति-प्रबन्धन-तन्त्राणि च परिवर्तयितुं न शक्यन्ते ।
नूतनानां C++ मानकविशेषतानां समर्थनं तुल्यकालिकरूपेण रूढिवादी अस्ति ।
समग्रतया, QWebSocket अधिकांश Tcp-आधारित WebSocket अनुप्रयोगानाम् कृते अतीव उत्तमं परिपक्वं च विकल्पं प्रदाति । उच्चविकासदक्षता च अल्पाः दोषाः च। QT अनुप्रयोगानाम् कृते अपि प्राधान्यम्। यदि उच्चस्तरीयाः आवश्यकताः सन्ति तर्हि अन्येषां अन्तर्निहितकार्यन्वयनानां विषये विचारः कर्तुं शक्यते । परन्तु अधिकांशप्रसङ्गेषु QWebSocket पर्याप्तं उत्तमम् अस्ति ।