QT示例:基于TCP 点对多Socket通讯(server,clients)
生活随笔
收集整理的這篇文章主要介紹了
QT示例:基于TCP 点对多Socket通讯(server,clients)
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
QT示例:基于TCP 點(diǎn)對(duì)多通訊(server,clients)
- 一、服務(wù)器server
- 二、客戶端Client
下載:基于TCP 點(diǎn)對(duì)多Socket通訊
一、服務(wù)器server
因?yàn)閷?duì)于客戶端來(lái)說(shuō),只能連接一個(gè)服務(wù)器。而對(duì)于服務(wù)器來(lái)說(shuō),它是面向多連接的,如何協(xié)調(diào)處理多客戶端連接就顯得尤為重要。
- 注意問(wèn)題:
每個(gè)新加入的客戶端,服務(wù)器給其分配一個(gè)SocketDescriptor后,就會(huì)emit newConnection()信號(hào),但分配好的SocketDecriptor并沒(méi)有通過(guò)newConnection()信號(hào)傳遞,所以用戶得不到這個(gè)客戶端標(biāo)識(shí)SocketDescriptor。同樣的,每當(dāng)服務(wù)器收到新的消息時(shí),客戶端會(huì)emit readReady()信號(hào),然而readReady()信號(hào)也沒(méi)有傳遞SocketDescriptor, 這樣的話,服務(wù)器端即使接收到消息,也不知道這個(gè)消息是從哪個(gè)客戶端發(fā)出的。 - 解決的方法:
本文示例為第二種方法:
1).pro 添加:
2)主函數(shù) 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);// 一 、創(chuàng)建QTcpSever對(duì)象;tcpServer = new QTcpServer(this);ui->edtIP->setText(QNetworkInterface().allAddresses().at(1).toString()); //獲取本地IPui->btnConnect->setEnabled(true);ui->btnSend->setEnabled(false);// 設(shè)置默認(rèn)按鈕樣式ui->btnConnect->setStyleSheet("");connect(tcpServer, &QTcpServer::newConnection, this, &MyTcpServer::NewConnectionSlot); }MyTcpServer::~MyTcpServer() {delete ui; }// 二、監(jiān)聽(tīng)--斷開(kāi) void MyTcpServer::on_btnConnect_clicked() {if(ui->btnConnect->text()=="監(jiān)聽(tīng)"){bool ok = tcpServer->listen(QHostAddress::Any, ui->edtPort->text().toInt());if(ok){ui->btnConnect->setText("斷開(kāi)");ui->btnConnect->setStyleSheet("color: red;");ui->btnSend->setEnabled(true);}}else{for(int i=0; i<tcpClient.length(); i++) // 斷開(kāi)所有連接{tcpClient[i]->disconnectFromHost();bool ok = tcpClient[i]->waitForDisconnected(1000);if(!ok){// 處理異常QMessageBox::warning(this, tr("錯(cuò)誤"),tr("斷開(kāi)連接失敗!"), QMessageBox::Ok);}tcpClient.removeAt(i); // 從保存的客戶端列表中取去除}tcpServer->close(); // 不再監(jiān)聽(tīng)端口ui->btnConnect->setText("監(jiān)聽(tīng)");ui->btnConnect->setStyleSheet("");ui->btnSend->setEnabled(false);} }// 三、新連接建立的槽函數(shù) 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); }// 四、客戶端數(shù)據(jù)可讀信號(hào),對(duì)應(yīng)的讀數(shù)據(jù)槽函數(shù) void MyTcpServer::ReadData() {// 由于readyRead信號(hào)并未提供SocketDecriptor,所以需要遍歷所有客戶端for(int i=0; i<tcpClient.length(); i++){QByteArray buffer = tcpClient[i]->readAll();if(buffer.isEmpty()) // 客戶端 數(shù)據(jù)為空,則跳過(guò)continue;// 客戶端有數(shù)據(jù)則 獲取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;} }// 五、斷開(kāi)連接的槽函數(shù) void MyTcpServer::disconnectedSlot() {//由于disconnected信號(hào)并未提供SocketDescriptor,所以需要遍歷尋找for(int i=0; i<tcpClient.length(); i++){if(tcpClient[i]->state() == QAbstractSocket::UnconnectedState){// 刪除存儲(chǔ)在combox中的客戶端信息ui->cbxConnection->removeItem(ui->cbxConnection->findText(tr("%1:%2").arg(tcpClient[i]->peerAddress().toString().split("::ffff:")[1]).arg(tcpClient[i]->peerPort())));// 刪除存儲(chǔ)在tcpClient列表中的客戶端信息tcpClient[i]->destroyed();tcpClient.removeAt(i);}} }// 六、發(fā)送數(shù)據(jù) void MyTcpServer::on_btnSend_clicked() {QString data = ui->edtSend->toPlainText();if(data == "")return; // 文本輸入框?yàn)榭諘r(shí)//全部連接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 端口號(hào) // 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唯一,無(wú)需繼續(xù)檢索}}} }// 清楚窗口 void MyTcpServer::on_btnClear_clicked() {ui->edtRecv->clear(); }5)界面 mytcpserver.ui
二、客戶端Client
1).pro 添加:
QT += network2)主函數(shù) 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://客戶端槽函數(shù)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); //實(shí)例化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)) // 連接成功則進(jìn)入if{}{ui->btnConnect->setText("斷開(kāi)");ui->btnSend->setEnabled(true);}}else{tcpClient->disconnectFromHost();if (tcpClient->state() == QAbstractSocket::UnconnectedState || tcpClient->waitForDisconnected(1000)) //已斷開(kāi)連接則進(jìn)入if{}{ui->btnConnect->setText("連接");ui->btnSend->setEnabled(false);}} }// 三、讀取數(shù)據(jù) void MyTcpClient::ReadData() {QByteArray buffer = tcpClient->readAll();if(!buffer.isEmpty()){ui->edtRecv->append(buffer);} }// 四、發(fā)送數(shù)據(jù) void MyTcpClient::on_btnSend_clicked() {QString data = ui->edtSend->toPlainText();if(data != ""){tcpClient->write(data.toLatin1()); //qt5出去了.toAscii()} }// 連接錯(cuò)誤信息處理 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網(wǎng)絡(luò)編程
總結(jié)
以上是生活随笔為你收集整理的QT示例:基于TCP 点对多Socket通讯(server,clients)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: MATLAB(二)数据的输入
- 下一篇: OpenCV学习笔记(一):Win10(