日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

QT示例:基于TCP 点对多Socket通讯(server,clients)

發布時間:2024/7/23 c/c++ 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 QT示例:基于TCP 点对多Socket通讯(server,clients) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

QT示例:基于TCP 點對多通訊(server,clients)

      • 一、服務器server
      • 二、客戶端Client

下載:基于TCP 點對多Socket通訊

一、服務器server

因為對于客戶端來說,只能連接一個服務器。而對于服務器來說,它是面向多連接的,如何協調處理多客戶端連接就顯得尤為重要。

  • 注意問題:
    每個新加入的客戶端,服務器給其分配一個SocketDescriptor后,就會emit newConnection()信號,但分配好的SocketDecriptor并沒有通過newConnection()信號傳遞,所以用戶得不到這個客戶端標識SocketDescriptor。同樣的,每當服務器收到新的消息時,客戶端會emit readReady()信號,然而readReady()信號也沒有傳遞SocketDescriptor, 這樣的話,服務器端即使接收到消息,也不知道這個消息是從哪個客戶端發出的。
  • 解決的方法:
  • 通過重寫==[virtual protected] void QTcpServer::incomingConnection(qintptr socketDescriptor)==,獲取soketDescriptor。自定義TcpClient類繼承QTcpSocket,并將獲得的soketDescriptor作為類成員。 這個方法的優點是:可以獲取到soketDescriptor,靈活性高。缺點是:需要重寫函數、自定義類。
  • 在newConnection()信號對應的槽函數中,通過QTcpSocket *QTcpServer::nextPendingConnection()函數獲取 新連接的客戶端:Returns the next pending connection as a connected QTcpSocket object. 雖然仍然得不到soketDescriptor,**但可以通過QTcpSocket類的peerAddress()和peerPort()成員函數獲取客戶端的IP和端口號,同樣是唯一標識。 **優點:無需重寫函數和自定義類,代碼簡潔。缺點:無法獲得SocketDecriptor,靈活性差。
  • 本文示例為第二種方法:
    1).pro 添加:

    QT += network

    2)主函數 main.cpp 添加:

    #include "mytcpserver.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);MyTcpServer w;w.show();return a.exec(); }

    3)MyTcpServer.h 添加:

    #include "mytcpserver.h" #include "ui_mytcpserver.h"MyTcpServer::MyTcpServer(QWidget *parent) :QMainWindow(parent),ui(new Ui::MyTcpServer) {ui->setupUi(this);// 一 、創建QTcpSever對象;tcpServer = new QTcpServer(this);ui->edtIP->setText(QNetworkInterface().allAddresses().at(1).toString()); //獲取本地IPui->btnConnect->setEnabled(true);ui->btnSend->setEnabled(false);// 設置默認按鈕樣式ui->btnConnect->setStyleSheet("");connect(tcpServer, &QTcpServer::newConnection, this, &MyTcpServer::NewConnectionSlot); }MyTcpServer::~MyTcpServer() {delete ui; }// 二、監聽--斷開 void MyTcpServer::on_btnConnect_clicked() {if(ui->btnConnect->text()=="監聽"){bool ok = tcpServer->listen(QHostAddress::Any, ui->edtPort->text().toInt());if(ok){ui->btnConnect->setText("斷開");ui->btnConnect->setStyleSheet("color: red;");ui->btnSend->setEnabled(true);}}else{for(int i=0; i<tcpClient.length(); i++) // 斷開所有連接{tcpClient[i]->disconnectFromHost();bool ok = tcpClient[i]->waitForDisconnected(1000);if(!ok){// 處理異常QMessageBox::warning(this, tr("錯誤"),tr("斷開連接失敗!"), QMessageBox::Ok);}tcpClient.removeAt(i); // 從保存的客戶端列表中取去除}tcpServer->close(); // 不再監聽端口ui->btnConnect->setText("監聽");ui->btnConnect->setStyleSheet("");ui->btnSend->setEnabled(false);} }// 三、新連接建立的槽函數 void MyTcpServer::NewConnectionSlot() {currentClient = tcpServer->nextPendingConnection();tcpClient.append(currentClient);ui->cbxConnection->addItem(tr("%1:%2").arg(currentClient->peerAddress().toString().split("::ffff:")[1]).arg(currentClient->peerPort()));connect(currentClient, &QTcpSocket::readyRead, this, &MyTcpServer::ReadData);connect(currentClient, &QTcpSocket::disconnected, this, &MyTcpServer::disconnectedSlot); }// 四、客戶端數據可讀信號,對應的讀數據槽函數 void MyTcpServer::ReadData() {// 由于readyRead信號并未提供SocketDecriptor,所以需要遍歷所有客戶端for(int i=0; i<tcpClient.length(); i++){QByteArray buffer = tcpClient[i]->readAll();if(buffer.isEmpty()) // 客戶端 數據為空,則跳過continue;// 客戶端有數據則 獲取IP 和端口static QString IP_Port, IP_Port_Pre;IP_Port = tr("[%1:%2]:").arg(tcpClient[i]->peerAddress().toString().split("::ffff:")[1]).arg(tcpClient[i]->peerPort());// 若此次消息的地址與上次不同,則需顯示此次消息的客戶端地址if(IP_Port != IP_Port_Pre)ui->edtRecv->append(IP_Port);ui->edtRecv->append(buffer);//更新ip_portIP_Port_Pre = IP_Port;} }// 五、斷開連接的槽函數 void MyTcpServer::disconnectedSlot() {//由于disconnected信號并未提供SocketDescriptor,所以需要遍歷尋找for(int i=0; i<tcpClient.length(); i++){if(tcpClient[i]->state() == QAbstractSocket::UnconnectedState){// 刪除存儲在combox中的客戶端信息ui->cbxConnection->removeItem(ui->cbxConnection->findText(tr("%1:%2").arg(tcpClient[i]->peerAddress().toString().split("::ffff:")[1]).arg(tcpClient[i]->peerPort())));// 刪除存儲在tcpClient列表中的客戶端信息tcpClient[i]->destroyed();tcpClient.removeAt(i);}} }// 六、發送數據 void MyTcpServer::on_btnSend_clicked() {QString data = ui->edtSend->toPlainText();if(data == "")return; // 文本輸入框為空時//全部連接if(ui->cbxConnection->currentIndex() == 0){for(int i=0; i<tcpClient.length(); i++)tcpClient[i]->write(data.toLatin1()); //qt5除去了.toAscii()}//指定連接else{QString clientIP = ui->cbxConnection->currentText().split(":")[0]; // IP 地址int clientPort = ui->cbxConnection->currentText().split(":")[1].toInt(); // port 端口號 // qDebug() << clientIP; // qDebug() << clientPort;for(int i=0; i<tcpClient.length(); i++){if(tcpClient[i]->peerAddress().toString().split("::ffff:")[1]==clientIP&& tcpClient[i]->peerPort()==clientPort){tcpClient[i]->write(data.toLatin1());return; //ip:port唯一,無需繼續檢索}}} }// 清楚窗口 void MyTcpServer::on_btnClear_clicked() {ui->edtRecv->clear(); }

    5)界面 mytcpserver.ui

    二、客戶端Client

    1).pro 添加:

    QT += network

    2)主函數 main.cpp 添加:

    #include "mytcpclient.h" #include <QApplication>int main(int argc, char *argv[]) {QApplication a(argc, argv);MyTcpClient w;w.show();return a.exec(); }

    3)MyTcpClient.h 添加:

    #include <QMainWindow> #include <QTcpSocket> #include <QHostAddress> #include <QMessageBox>namespace Ui { class MyTcpClient; }class MyTcpClient : public QMainWindow {Q_OBJECTpublic:explicit MyTcpClient(QWidget *parent = 0);~MyTcpClient();private:Ui::MyTcpClient *ui;QTcpSocket *tcpClient;private slots://客戶端槽函數void ReadData();void ReadError(QAbstractSocket::SocketError);void on_btnConnect_clicked();void on_btnSend_clicked();void on_pushButton_clicked(); };

    4)MyTcpClient.cpp 添加:

    #include "mytcpclient.h" #include "ui_mytcpclient.h"MyTcpClient::MyTcpClient(QWidget *parent) :QMainWindow(parent),ui(new Ui::MyTcpClient) {ui->setupUi(this);// 一、初始化TCP客戶端tcpClient = new QTcpSocket(this); //實例化tcpClienttcpClient->abort(); //取消原有連接ui->btnConnect->setEnabled(true);ui->btnSend->setEnabled(false);connect(tcpClient, &QTcpSocket::readyRead, this, &MyTcpClient::ReadData);connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(ReadError(QAbstractSocket::SocketError))); }MyTcpClient::~MyTcpClient() {delete ui; }// 二、連接 void MyTcpClient::on_btnConnect_clicked() {if(ui->btnConnect->text()=="連接"){tcpClient->connectToHost(ui->edtIP->text(), ui->edtPort->text().toInt());if (tcpClient->waitForConnected(1000)) // 連接成功則進入if{}{ui->btnConnect->setText("斷開");ui->btnSend->setEnabled(true);}}else{tcpClient->disconnectFromHost();if (tcpClient->state() == QAbstractSocket::UnconnectedState || tcpClient->waitForDisconnected(1000)) //已斷開連接則進入if{}{ui->btnConnect->setText("連接");ui->btnSend->setEnabled(false);}} }// 三、讀取數據 void MyTcpClient::ReadData() {QByteArray buffer = tcpClient->readAll();if(!buffer.isEmpty()){ui->edtRecv->append(buffer);} }// 四、發送數據 void MyTcpClient::on_btnSend_clicked() {QString data = ui->edtSend->toPlainText();if(data != ""){tcpClient->write(data.toLatin1()); //qt5出去了.toAscii()} }// 連接錯誤信息處理 void MyTcpClient::ReadError(QAbstractSocket::SocketError) {tcpClient->disconnectFromHost();ui->btnConnect->setText(tr("連接"));QMessageBox msgBox;msgBox.setText(tr("failed to connect server because %1").arg(tcpClient->errorString()));msgBox.exec(); }// 清空按鈕 void MyTcpClient::on_pushButton_clicked() {ui->edtRecv->clear(); }

    2)mytcpclient.ui 添加


    參考博客:
    QT 之TCP網絡編程

    總結

    以上是生活随笔為你收集整理的QT示例:基于TCP 点对多Socket通讯(server,clients)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。