QT示例:基于TCP 点对多Socket通讯(server,clients)
生活随笔
收集整理的這篇文章主要介紹了
QT示例:基于TCP 点对多Socket通讯(server,clients)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
QT示例:基于TCP 點對多通訊(server,clients)
- 一、服務器server
- 二、客戶端Client
下載:基于TCP 點對多Socket通訊
一、服務器server
因為對于客戶端來說,只能連接一個服務器。而對于服務器來說,它是面向多連接的,如何協調處理多客戶端連接就顯得尤為重要。
- 注意問題:
每個新加入的客戶端,服務器給其分配一個SocketDescriptor后,就會emit newConnection()信號,但分配好的SocketDecriptor并沒有通過newConnection()信號傳遞,所以用戶得不到這個客戶端標識SocketDescriptor。同樣的,每當服務器收到新的消息時,客戶端會emit readReady()信號,然而readReady()信號也沒有傳遞SocketDescriptor, 這樣的話,服務器端即使接收到消息,也不知道這個消息是從哪個客戶端發出的。 - 解決的方法:
本文示例為第二種方法:
1).pro 添加:
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 += network2)主函數 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)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MATLAB(二)数据的输入
- 下一篇: OpenCV学习笔记(一):Win10(