qt triggered信号_Qt之网络编程UDP通信
點擊上方“Qt學(xué)視覺”,選擇“星標(biāo)”公眾號重磅干貨,第一時間送達
想要學(xué)習(xí)的同學(xué)們還請認(rèn)真閱讀每篇文章,相信你一定會有所收獲
UDP通信概述
?? ? UDP(UserDatagramProtocol,用戶數(shù)據(jù)報協(xié)議)是輕量的、不可靠的、面向數(shù)據(jù)報(datagram)、無連接的協(xié)議,它可以用于對可靠性要求不高的場合與TCP通信不同,兩個程序之間進行UDP通信無 需預(yù)先建立持久的socket連接,UDP每次發(fā)送數(shù)據(jù)報都需要指定目標(biāo)地址和端口(如下圖所示)。?
?? ?QUdpSocket類用于實現(xiàn)UDP通信,它從QAbstractSocket類繼承,因而與QTcpSocket共享 大部分的接口函數(shù)。主要區(qū)別是QUdpSocket以數(shù)據(jù)報傳輸數(shù)據(jù),而不是以連續(xù)的數(shù)據(jù)流。發(fā)送數(shù) 據(jù)報使用函數(shù)QUdpSocket::writeDatagram(),數(shù)據(jù)報的長度一般少于512字節(jié),每個數(shù)據(jù)報包含發(fā) 送者和接收者的IP地址和端口等信息。?
?? ?要進行UDP數(shù)據(jù)接收,要用QUdpSocket::bind()函數(shù)先綁定一個端口,用于接收傳入的數(shù)據(jù) 報。當(dāng)有數(shù)據(jù)報傳入時會發(fā)射readyRead()信號,使用readDatagram()函數(shù)來讀取接收到的數(shù)據(jù)報。UDP消息傳送有單播、廣播、組播三種模式
單播(unicast)模式:一個UDP客戶端發(fā)出的數(shù)據(jù)報只發(fā)送到另一個指定地址和端口的 UDP客戶端,是一對一的數(shù)據(jù)傳輸。
廣播(broadcast)模式:一個UDP客戶端發(fā)出的數(shù)據(jù)報,在同一網(wǎng)絡(luò)范圍內(nèi)其他所有的UDP客戶端都可以收到。QUdpSocket支持IPv4廣播。廣播經(jīng)常用于實現(xiàn)網(wǎng)絡(luò)發(fā)現(xiàn)的協(xié)議。要獲取廣播數(shù)據(jù)只需在數(shù)據(jù)報中指定接收端地址為QHostAddres::Broadcast, —般的廣播 地址是 255.255.255.255。
組播(multicast)模式:也稱為多播。UDP客戶端加入到另一個組播IP地址指定的多播 組,成員向組播地址發(fā)送的數(shù)據(jù)報組內(nèi)成員都可以接收到,類似于QQ群的功能. QUdpSocket::joinMulticastGroup()函數(shù)實現(xiàn)加入多播組的功能,加入多播組后,UDP數(shù)據(jù) 的收發(fā)與正常的UDP數(shù)據(jù)收發(fā)方法一樣。
?? ?使用廣播和多播模式,UDP可以實現(xiàn)一些比較靈活的通信功能,而TCP通信只有單播模式, 沒有廣播和多播模式。所以,UDP通信雖然不能保證數(shù)據(jù)傳輸?shù)臏?zhǔn)確性,但是具有靈活性,一般 的即時通信軟件都是基于UDP通信的。?
?? ?QUdpSocket類從QAbstractSocket繼承而來,但是又定義了較多新的功能函數(shù)用于實現(xiàn)UDP 特有的一些功能,如數(shù)據(jù)報讀寫和多播通信功能。QUdpSocket沒有定義新的信號。QUdpSocket 的主要功能函數(shù)見表
bool bind(quint 16 port = 0)
為UDP通信綁定一個端口
qint64 writeDatagram(QByteArray &datagram, QHostAddress &host, quint 16 port)
向目標(biāo)地址和端口的UDP客戶端發(fā)送數(shù)據(jù)報,返回成功 發(fā)送的字節(jié)數(shù)
bool hasPendingDatagrams()
當(dāng)至少有一個數(shù)據(jù)報需要讀取時,返回true
qint64 pendingDatagramSize()
返回第一個待讀取的數(shù)據(jù)報的大小
qint64 readDatagram(char *data, qint64 maxSize)
讀取一個數(shù)據(jù)報,返回成功讀取的數(shù)據(jù)報的字節(jié)數(shù)
bool joinMulticastGroup(QHostAddress &groupAddress)
加入一個多播組
bool leaveMulticastGroup(QHostAddress &groupAddress)? ? ?
離開一個多播組
?? ?在單播、廣播和多播模式下,UDP程序都是對等的,不像TCP通信那樣分為客戶端和服務(wù)器 端。多播和廣播的實現(xiàn)方式基本相同,只是數(shù)據(jù)報的目標(biāo)IP地址設(shè)置不同,多播模式需要加入多 播組,實現(xiàn)方式有較大差異。
例程如下
頭文件
#pragma once#include #include "ui_QGuiUdpClient.h"#include #include class QGuiUdpClient : public QMainWindow{ Q_OBJECTpublic: QGuiUdpClient(QWidget *parent = Q_NULLPTR); ~QGuiUdpClient();private slots: //自定義槽函數(shù) void onSocketStateChange(QAbstractSocket::SocketState socketState); void onSocketReadyRead();//讀取socket傳入的數(shù)據(jù) void actStart_triggered(); void actStop_triggered(); void actHostInfo_triggered(); void actClear_triggered(); void btnSend_clicked(); void btnBroadcast_clicked();private: Ui::QGuiUdpClient ui;private: QLabel* m_pLabSocketState;//socket狀態(tài)顯示標(biāo)簽 QUdpSocket* m_pUdpSocket;// QString getLocalIP();//獲取本機IP地址};源文件
#include "QGuiUdpClient.h"#include #pragma execution_character_set("utf-8")QGuiUdpClient::QGuiUdpClient(QWidget *parent) : QMainWindow(parent){ ui.setupUi(this); m_pLabSocketState = new QLabel("Socket狀態(tài):");// m_pLabSocketState->setMinimumWidth(200); ui.statusBar->addWidget(m_pLabSocketState); QString localIP = getLocalIP();//本機IP this->setWindowTitle(this->windowTitle() + "----本機IP:" + localIP); ui.comboTargetIP->addItem(localIP); m_pUdpSocket = new QUdpSocket(this);//用于與連接的客戶端通訊的QTcpSocket connect(m_pUdpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChange(QAbstractSocket::SocketState))); onSocketStateChange(m_pUdpSocket->state()); connect(m_pUdpSocket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead())); connect(ui.actStart, SIGNAL(triggered()), this, SLOT(actStart_triggered())); connect(ui.actStop, SIGNAL(triggered()), this, SLOT(actStop_triggered())); connect(ui.actHostInfo, SIGNAL(triggered()), this, SLOT(actHostInfo_triggered())); connect(ui.actClear, SIGNAL(triggered()), this, SLOT(actClear_triggered())); connect(ui.btnSend, SIGNAL(clicked()), this, SLOT(btnSend_clicked())); connect(ui.btnBroadcast, SIGNAL(clicked()), this, SLOT(btnBroadcast_clicked()));}QGuiUdpClient::~QGuiUdpClient(){ m_pUdpSocket->abort(); delete m_pUdpSocket;}void QGuiUdpClient::onSocketStateChange(QAbstractSocket::SocketState socketState){ switch (socketState) { case QAbstractSocket::UnconnectedState: m_pLabSocketState->setText("scoket狀態(tài):UnconnectedState"); break; case QAbstractSocket::HostLookupState: m_pLabSocketState->setText("scoket狀態(tài):HostLookupState"); break; case QAbstractSocket::ConnectingState: m_pLabSocketState->setText("scoket狀態(tài):ConnectingState"); break; case QAbstractSocket::ConnectedState: m_pLabSocketState->setText("scoket狀態(tài):ConnectedState"); break; case QAbstractSocket::BoundState: m_pLabSocketState->setText("scoket狀態(tài):BoundState"); break; case QAbstractSocket::ClosingState: m_pLabSocketState->setText("scoket狀態(tài):ClosingState"); break; case QAbstractSocket::ListeningState: m_pLabSocketState->setText("scoket狀態(tài):ListeningState"); break; }}void QGuiUdpClient::onSocketReadyRead(){ while (m_pUdpSocket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(m_pUdpSocket->pendingDatagramSize()); QHostAddress peerAddr; quint16 peerPort; m_pUdpSocket->readDatagram(datagram.data(), datagram.size(), &peerAddr, &peerPort); QString str = datagram.data(); QString peer = "[From " + peerAddr.toString() + ":" + QString::number(peerPort) + "] "; ui.plainTextEdit->appendPlainText(peer + str); }}void QGuiUdpClient::actStart_triggered(){ quint16 port = ui.spinBindPort->value(); //本機UDP端口 if (m_pUdpSocket->bind(port))//綁定端口成功 { ui.plainTextEdit->appendPlainText("**已成功綁定"); ui.plainTextEdit->appendPlainText("**綁定端口:" + QString::number(m_pUdpSocket->localPort())); ui.actStart->setEnabled(false); ui.actStop->setEnabled(true); } else ui.plainTextEdit->appendPlainText("**綁定失敗");}void QGuiUdpClient::actStop_triggered(){ m_pUdpSocket->abort(); //不能解除綁定 ui.actStart->setEnabled(true); ui.actStop->setEnabled(false); ui.plainTextEdit->appendPlainText("**已解除綁定");}void QGuiUdpClient::actHostInfo_triggered(){ QString hostName = QHostInfo::localHostName();//本地主機名 ui.plainTextEdit->appendPlainText("本機主機名:" + hostName + "\n"); QHostInfo hostInfo = QHostInfo::fromName(hostName); QList addList = hostInfo.addresses();// if (!addList.isEmpty()) { for (int i = 0; i < addList.count(); i++) { QHostAddress aHost = addList.at(i); if (QAbstractSocket::IPv4Protocol == aHost.protocol()) { QString IP = aHost.toString(); ui.plainTextEdit->appendPlainText("本機IP地址:" + aHost.toString()); if (ui.comboTargetIP->findText(IP) < 0) ui.comboTargetIP->addItem(IP); } } }}void QGuiUdpClient::actClear_triggered(){ ui.plainTextEdit->clear();}void QGuiUdpClient::btnSend_clicked(){ QString targetIP = ui.comboTargetIP->currentText(); //目標(biāo)IP QHostAddress targetAddr(targetIP); quint16 targetPort = ui.spinTargetPort->value();//目標(biāo)port QString msg = ui.editMsg->text();//發(fā)送的消息內(nèi)容 QByteArray str = msg.toUtf8(); m_pUdpSocket->writeDatagram(str, targetAddr, targetPort); //發(fā)出數(shù)據(jù)報 ui.plainTextEdit->appendPlainText("[out] " + msg); ui.editMsg->clear(); ui.editMsg->setFocus();}void QGuiUdpClient::btnBroadcast_clicked(){ quint16 targetPort = ui.spinTargetPort->value(); //目標(biāo)端口 QString msg = ui.editMsg->text(); QByteArray str = msg.toUtf8(); m_pUdpSocket->writeDatagram(str, QHostAddress::Broadcast, targetPort); ui.plainTextEdit->appendPlainText("[broadcast] " + msg); ui.editMsg->clear(); ui.editMsg->setFocus();}QString QGuiUdpClient::getLocalIP(){ QString hostName = QHostInfo::localHostName();//本地主機名 QHostInfo hostInfo = QHostInfo::fromName(hostName); QString localIP = ""; QList addList = hostInfo.addresses();// if (!addList.isEmpty()) { for (int i = 0; i < addList.count(); i++) { QHostAddress aHost = addList.at(i); if (QAbstractSocket::IPv4Protocol == aHost.protocol()) { localIP = aHost.toString(); break; } } } return localIP;}頭文件
#pragma once#include #include "ui_QGuiUdpServer.h"#include #include class QGuiUdpServer : public QMainWindow{ Q_OBJECTpublic: QGuiUdpServer(QWidget *parent = Q_NULLPTR); ~QGuiUdpServer();private slots: //自定義槽函數(shù) void onSocketStateChange(QAbstractSocket::SocketState socketState); void onSocketReadyRead();//讀取socket傳入的數(shù)據(jù) void actStart_triggered(); void actStop_triggered(); void actHostInfo_triggered(); void actClear_triggered(); void btnSend_clicked(); void btnBroadcast_clicked();private: Ui::QGuiUdpServer ui;private: QLabel* m_pLabSocketState;//socket狀態(tài)顯示標(biāo)簽 QUdpSocket* m_pUdpSocket;// QString getLocalIP();//獲取本機IP地址};源文件
#include "QGuiUdpServer.h"#include #pragma execution_character_set("utf-8")QGuiUdpServer::QGuiUdpServer(QWidget *parent) : QMainWindow(parent){ ui.setupUi(this); m_pLabSocketState = new QLabel("Socket狀態(tài):");// m_pLabSocketState->setMinimumWidth(200); ui.statusBar->addWidget(m_pLabSocketState); QString localIP = getLocalIP();//本機IP this->setWindowTitle(this->windowTitle() + "----本機IP:" + localIP); ui.comboTargetIP->addItem(localIP); m_pUdpSocket = new QUdpSocket(this);//用于與連接的客戶端通訊的QTcpSocket connect(m_pUdpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChange(QAbstractSocket::SocketState))); onSocketStateChange(m_pUdpSocket->state()); connect(m_pUdpSocket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead())); connect(ui.actStart, SIGNAL(triggered()), this, SLOT(actStart_triggered())); connect(ui.actStop, SIGNAL(triggered()), this, SLOT(actStop_triggered())); connect(ui.actHostInfo, SIGNAL(triggered()), this, SLOT(actHostInfo_triggered())); connect(ui.actClear, SIGNAL(triggered()), this, SLOT(actClear_triggered())); connect(ui.btnSend, SIGNAL(clicked()), this, SLOT(btnSend_clicked())); connect(ui.btnBroadcast, SIGNAL(clicked()), this, SLOT(btnBroadcast_clicked()));}QGuiUdpServer::~QGuiUdpServer(){ m_pUdpSocket->abort(); delete m_pUdpSocket;}void QGuiUdpServer::onSocketStateChange(QAbstractSocket::SocketState socketState){ switch (socketState) { case QAbstractSocket::UnconnectedState: m_pLabSocketState->setText("scoket狀態(tài):UnconnectedState"); break; case QAbstractSocket::HostLookupState: m_pLabSocketState->setText("scoket狀態(tài):HostLookupState"); break; case QAbstractSocket::ConnectingState: m_pLabSocketState->setText("scoket狀態(tài):ConnectingState"); break; case QAbstractSocket::ConnectedState: m_pLabSocketState->setText("scoket狀態(tài):ConnectedState"); break; case QAbstractSocket::BoundState: m_pLabSocketState->setText("scoket狀態(tài):BoundState"); break; case QAbstractSocket::ClosingState: m_pLabSocketState->setText("scoket狀態(tài):ClosingState"); break; case QAbstractSocket::ListeningState: m_pLabSocketState->setText("scoket狀態(tài):ListeningState"); break; }}void QGuiUdpServer::onSocketReadyRead(){ while (m_pUdpSocket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(m_pUdpSocket->pendingDatagramSize()); QHostAddress peerAddr; quint16 peerPort; m_pUdpSocket->readDatagram(datagram.data(), datagram.size(), &peerAddr, &peerPort); QString str = datagram.data(); QString peer = "[From " + peerAddr.toString() + ":" + QString::number(peerPort) + "] "; ui.plainTextEdit->appendPlainText(peer + str); }}void QGuiUdpServer::actStart_triggered(){ quint16 port = ui.spinBindPort->value(); //本機UDP端口 if (m_pUdpSocket->bind(port))//綁定端口成功 { ui.plainTextEdit->appendPlainText("**已成功綁定"); ui.plainTextEdit->appendPlainText("**綁定端口:" + QString::number(m_pUdpSocket->localPort())); ui.actStart->setEnabled(false); ui.actStop->setEnabled(true); } else ui.plainTextEdit->appendPlainText("**綁定失敗");}void QGuiUdpServer::actStop_triggered(){ m_pUdpSocket->abort(); //不能解除綁定 ui.actStart->setEnabled(true); ui.actStop->setEnabled(false); ui.plainTextEdit->appendPlainText("**已解除綁定");}void QGuiUdpServer::actHostInfo_triggered(){ QString hostName = QHostInfo::localHostName();//本地主機名 ui.plainTextEdit->appendPlainText("本機主機名:" + hostName + "\n"); QHostInfo hostInfo = QHostInfo::fromName(hostName); QList addList = hostInfo.addresses();// if (!addList.isEmpty()) { for (int i = 0; i < addList.count(); i++) { QHostAddress aHost = addList.at(i); if (QAbstractSocket::IPv4Protocol == aHost.protocol()) { QString IP = aHost.toString(); ui.plainTextEdit->appendPlainText("本機IP地址:" + aHost.toString()); if (ui.comboTargetIP->findText(IP) < 0) ui.comboTargetIP->addItem(IP); } } }}void QGuiUdpServer::actClear_triggered(){ ui.plainTextEdit->clear();}void QGuiUdpServer::btnSend_clicked(){ QString targetIP = ui.comboTargetIP->currentText(); //目標(biāo)IP QHostAddress targetAddr(targetIP); quint16 targetPort = ui.spinTargetPort->value();//目標(biāo)port QString msg = ui.editMsg->text();//發(fā)送的消息內(nèi)容 QByteArray str = msg.toUtf8(); m_pUdpSocket->writeDatagram(str, targetAddr, targetPort); //發(fā)出數(shù)據(jù)報 ui.plainTextEdit->appendPlainText("[out] " + msg); ui.editMsg->clear(); ui.editMsg->setFocus();}void QGuiUdpServer::btnBroadcast_clicked(){ quint16 targetPort = ui.spinTargetPort->value(); //目標(biāo)端口 QString msg = ui.editMsg->text(); QByteArray str = msg.toUtf8(); m_pUdpSocket->writeDatagram(str, QHostAddress::Broadcast, targetPort); ui.plainTextEdit->appendPlainText("[broadcast] " + msg); ui.editMsg->clear(); ui.editMsg->setFocus();}QString QGuiUdpServer::getLocalIP(){ QString hostName = QHostInfo::localHostName();//本地主機名 QHostInfo hostInfo = QHostInfo::fromName(hostName); QString localIP = ""; QList addList = hostInfo.addresses();// if (!addList.isEmpty()) { for (int i = 0; i < addList.count(); i++) { QHostAddress aHost = addList.at(i); if (QAbstractSocket::IPv4Protocol == aHost.protocol()) { localIP = aHost.toString(); break; } } } return localIP;}總結(jié)
以上是生活随笔為你收集整理的qt triggered信号_Qt之网络编程UDP通信的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 黄焖鱼的家常做法
- 下一篇: 「达人分享」40码是uk多少