qt tcp通信_Qt之网络编程TCP通信
點(diǎn)擊上方“Qt學(xué)視覺”,選擇“星標(biāo)”公眾號(hào)重磅干貨,第一時(shí)間送達(dá)
想要學(xué)習(xí)的同學(xué)們還請(qǐng)認(rèn)真閱讀每篇文章,相信你一定會(huì)有所收獲
TCP通信概述
? ?TCP(Transmission Control Protocol)是一種被大多數(shù) Internet 網(wǎng)絡(luò)協(xié)議(如 HTTP 和 FTP)用于 數(shù)據(jù)傳輸?shù)牡图?jí)網(wǎng)絡(luò)協(xié)議,它是可靠的、面向流、面向連接的傳輸協(xié)議,特別適合用于連續(xù)數(shù)據(jù)傳輸。
? ?TCP通信必須先建立TCP連接,通信端分為客戶端和服務(wù)器端。
? ?Qt提供 QTcpSocket類和QTcpServer類用于建立TCP通信應(yīng)用程 TCP Client 序。
? ?服務(wù)器端程序必須使用QTcpServer用于端口監(jiān)聽,建 立服務(wù)器;
? ?QTcpSocket用于建立連接后使用套接字(Socket) 進(jìn)行通信。
? ?QTcpServer是從QObject繼承的類,它主要用于服務(wù)器端建立網(wǎng)絡(luò)監(jiān)聽,創(chuàng)建網(wǎng)絡(luò)Socket連 接。QTcpServer類的主要接口函數(shù)見表
void close()
關(guān)閉服務(wù)器,停止網(wǎng)絡(luò)監(jiān)聽
bool listen()
在給定IP地址和端口上開始監(jiān)聽,若成功就返回true
bool isListening()
返回true表示服務(wù)器處于監(jiān)聽狀態(tài)
QTcpSocket * nextPendingConnection()
返回下一個(gè)等待接入的連接
QHostAddress serverAddress()
如果服務(wù)器處于監(jiān)聽狀態(tài),返回服務(wù)器地址
quint 16 serverPort()
如果服務(wù)器處于監(jiān)聽狀態(tài),返回服務(wù)器監(jiān)聽端口
bool waitForNewConnection()
以阻塞方式等待新的連接 信號(hào)
void acceptError( QAbstractSocket::SocketError socketError)
當(dāng)接受一個(gè)新的連接發(fā)生錯(cuò)誤時(shí)發(fā)射此信號(hào),參數(shù) socketError描述了錯(cuò)誤信息
void newConnection()
?當(dāng)有新的連接時(shí)發(fā)射此信號(hào)
void incomingConnection(qintptr socketDescriptor)
當(dāng)有一個(gè)新的連接可用時(shí),QTcpServer內(nèi)部調(diào)用此函數(shù),創(chuàng) 建一個(gè)QTcpSocket對(duì)象,添加到內(nèi)部可用新連接列表,然 后發(fā)射newConnection()信號(hào)。用戶若從QTcpServer繼承定 義類,可以重定義此函數(shù),但必須調(diào)用 addPendingConnection()
void addPendingConnection(QTcpSocket ?socket)
由 incomingConnection()調(diào)用,將創(chuàng)建的 QTcpSocket 添加到 內(nèi)部新可用連接列表
?? ?服務(wù)器端程序首先需要用QTcpServendisten()開始服務(wù)器端監(jiān)聽,可以指定監(jiān)聽的IP地址和 端口,一般一個(gè)服務(wù)程序只監(jiān)聽某個(gè)端口的網(wǎng)絡(luò)連接。
?? ?當(dāng)有新的客戶端接入時(shí),QTcpServer內(nèi)部的incomingConnection()函數(shù)會(huì)創(chuàng)建一個(gè)與客戶端連 接的QTcpSocket對(duì)象,然后發(fā)射信號(hào)newConnection()。在newConnection()信號(hào)的槽函數(shù)中,可以用nextPendingConnection()接受客戶端的連接,然后使用QTcpSocket與客戶端通信。?? ??? ?
?? ?所以在客戶端與服務(wù)器建立TCP連接后,具體的數(shù)據(jù)通信是通過QTcpSocket完成的。QTcpSocket類提供了 TCP協(xié)議的接口,可以用QTcpSocket類實(shí)現(xiàn)標(biāo)準(zhǔn)的網(wǎng)絡(luò)通信協(xié)議如POP3、 SMTP和NNTP,也可以設(shè)計(jì)自定義協(xié)議。?
?? ?QTcpSocket是從QIODevice間接繼承的類,所以具有流讀寫的功能
?? ?
QTcpSocket類除了構(gòu)造函數(shù)和析構(gòu)函數(shù),其他函數(shù)都是從QAbstractSocket繼承或重定義的。QAbstractSocket用于TCP通信的主要接口函數(shù)見表
void connectToHost(QHostAddress?&address, quint 16 port,)
以異步方式連接到指定IP地址和端口的TCP服務(wù)器,連接成功? 后會(huì)發(fā)射connected()信號(hào)
void disconnectFromHost()
斷開socket,關(guān)閉成功后發(fā)射disconnected()信號(hào)
bool waitForConnected()
等待直到建立socket連接
bool waitForDisconnected()
等待直到斷開socket連接
QHostAddress localAddress()
返回本socket的地址
quint 16 localPort()
返回本socket的端口
QHostAddress peerAddress()
在已連接狀態(tài)下,返回對(duì)方socket的地址
QString peerName()
返回connectToHost()連接到的對(duì)方的主機(jī)名
quintl6 peerPort()
在已連接狀態(tài)下,返回對(duì)方socket的端口
qint64 readBufferSize()
返回內(nèi)部讀取緩沖區(qū)的大小,該大小決定了 read()和 readAII()函數(shù)能讀出的數(shù)據(jù)的大小
void setReadBufferSize(qint64 size)
設(shè)置內(nèi)部讀取緩沖區(qū)大小
qint64 bytesAvailable()
返回需要讀取的緩沖區(qū)的數(shù)據(jù)的字節(jié)數(shù)
bool canReadLine()
如果有行數(shù)據(jù)要從socket緩沖區(qū)讀取,就返回true
SocketState state()
返回socket當(dāng)前的狀態(tài)
void connected()
connectToHost()成功連接到服務(wù)器后發(fā)射此信號(hào)
void disconnected()
當(dāng)socket斷開連接后發(fā)射此信號(hào)
void error(QAbstractSocket::SocketError socketError)
當(dāng)socket發(fā)生錯(cuò)誤時(shí)發(fā)射此信號(hào)
void hostFound()
調(diào)用connectToHost()找到主機(jī)后發(fā)射此信號(hào)
void stateChanged(QAbstractSocket::SocketState socketState)
當(dāng) socket的狀態(tài)變化時(shí)發(fā)射此信號(hào),參數(shù)socketState表示了socket 當(dāng)前的狀態(tài)
void readyRead()
當(dāng)緩沖區(qū)有新數(shù)據(jù)需要讀取時(shí)發(fā)射此信號(hào),在此信號(hào)的槽函數(shù)里 讀取緩沖區(qū)的數(shù)據(jù)
?? ?TCP客戶端使用QTcpSocket與TCP服務(wù)器建立連接并通信
?? ?客戶端的QTcpSocket實(shí)例首先通過connectToHost()嘗試連接到服務(wù)器,需要指定服務(wù)器的IP地址和端口.connectToHost()是異步方式連接服務(wù)器,不會(huì)阻塞程序運(yùn)行,連接后發(fā)射connected()信號(hào)。
?? ?如果需要使用阻塞方式連接服務(wù)器,則使用waitForConnected()函數(shù)阻塞程序運(yùn)行,直到連接 成功或失敗。例如:?
socket->connectToHost("192.168.1.100", 1340); if (socket->waitForConnected(1000)) qDebug("Connected!");?? ?與服務(wù)器端建立socket連接后,就可以向緩沖區(qū)寫數(shù)據(jù)或從接收緩沖區(qū)讀取數(shù)據(jù),實(shí)現(xiàn)數(shù)據(jù)的通信。當(dāng)緩沖區(qū)有新數(shù)據(jù)進(jìn)入時(shí),會(huì)發(fā)射readyRead()信號(hào),一般在此信號(hào)的槽函數(shù)里讀取緩沖區(qū)數(shù)據(jù)。
?? ?QTcpSocket是從QIODevice間接繼承的,所以可以使用流數(shù)據(jù)讀寫功能。—個(gè)QTcpSocket 實(shí)例既可以接收數(shù)據(jù)也可以發(fā)送數(shù)據(jù),且接收與發(fā)射是異步工作的,有各自的緩沖區(qū)。?
?? ?作為演示TCP通信的實(shí)例,創(chuàng)建了一個(gè)TCPClient程序和一個(gè)TCPServer程序
TCPServer程序具有如下的功能:?
?? ??根據(jù)指定IP地址(本機(jī)地址)和端口打開網(wǎng)絡(luò)監(jiān)聽,有客戶端連接時(shí)創(chuàng)建socket連接;?
?? ??采用基于行的數(shù)據(jù)通信協(xié)議,可以接收客戶端發(fā)來的消息,也可以向客戶端發(fā)送消息;?
?? ??在狀態(tài)欄顯示服務(wù)器監(jiān)聽狀態(tài)和socket的狀態(tài)。?
頭文件
#pragma once#include #include "Ui_QGuiTcpServer.h"#include #include #include class QGuiTcpServer : public QMainWindow{ Q_OBJECTpublic: QGuiTcpServer(QWidget *parent = Q_NULLPTR); ~QGuiTcpServer();private slots: void actStart_triggered();//開始監(jiān)聽 void actStop_triggered(); void actHostInfo_triggered(); void actClear_triggered(); void btnSend_clicked(); void onNewConnection(); void onSocketStateChange(QAbstractSocket::SocketState socketState); void onClientConnected(); //Client Socket connected void onClientDisconnected();//Client Socket disconnected void onSocketReadyRead();//讀取socket傳入的數(shù)據(jù)private: Ui::QTcpServer ui;protected: void closeEvent(QCloseEvent* event);private: QLabel* m_pLabListen;//狀態(tài)欄標(biāo)簽 QLabel* m_pLabSocketState;//狀態(tài)欄標(biāo)簽 QTcpServer* m_pTcpServer;//tcp服務(wù)器 QTcpSocket* m_pTcpSocket;//tcp通信的Socket QString getLocalIP();//獲取本機(jī)IP地址};源文件
#include "QGuiTcpServer.h"#include #include #pragma execution_character_set("utf-8")QGuiTcpServer::QGuiTcpServer(QWidget *parent) : QMainWindow(parent){ ui.setupUi(this); m_pLabListen = new QLabel("監(jiān)聽狀態(tài):"); m_pLabListen->setMinimumWidth(150); ui.statusBar->addWidget(m_pLabListen); m_pLabSocketState = new QLabel("狀態(tài):"); m_pLabSocketState->setMinimumWidth(200); ui.statusBar->addWidget(m_pLabSocketState); QString localIP = getLocalIP();//本機(jī)IP setWindowTitle(windowTitle() + "----本機(jī)IP:" + localIP); ui.comboIP->addItem(localIP); m_pTcpServer = new QTcpServer(this); connect(m_pTcpServer, SIGNAL(newConnection()), this, SLOT(onNewConnection())); 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()));}QGuiTcpServer::~QGuiTcpServer(){}//開始監(jiān)聽void QGuiTcpServer::actStart_triggered(){ QString IP = ui.comboIP->currentText();//IP地址 quint16 port = ui.spinPort->value();//端口 QHostAddress addr(IP); m_pTcpServer->listen(addr, port);// //m_pLabListen->listen(QHostAddress::LocalHost,port);// Equivalent to QHostAddress("127.0.0.1"). ui.plainTextEdit->appendPlainText("**開始監(jiān)聽..."); ui.plainTextEdit->appendPlainText("**服務(wù)器地址:"+ m_pTcpServer->serverAddress().toString()); ui.plainTextEdit->appendPlainText("**服務(wù)器端口:"+ QString::number(m_pTcpServer->serverPort())); ui.actStart->setEnabled(false); ui.actStop->setEnabled(true); m_pLabListen->setText("監(jiān)聽狀態(tài):正在監(jiān)聽");}void QGuiTcpServer::actStop_triggered(){ if (m_pTcpServer->isListening()) //tcpServer正在監(jiān)聽 { m_pTcpServer->close();//停止監(jiān)聽 ui.actStart->setEnabled(true); ui.actStop->setEnabled(false); m_pLabListen->setText("監(jiān)聽狀態(tài):已停止監(jiān)聽"); }}void QGuiTcpServer::actHostInfo_triggered(){ QString hostName = QHostInfo::localHostName();//本地主機(jī)名 ui.plainTextEdit->appendPlainText("本機(jī)主機(jī)名:" + 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("本機(jī)IP地址:" + aHost.toString()); if (ui.comboIP->findText(IP) < 0) ui.comboIP->addItem(IP); } } }}void QGuiTcpServer::actClear_triggered(){ ui.plainTextEdit->clear();}void QGuiTcpServer::btnSend_clicked(){ QString msg = ui.editMsg->text(); ui.plainTextEdit->appendPlainText("[out] " + msg); ui.editMsg->clear(); ui.editMsg->setFocus(); QByteArray str = msg.toUtf8(); str.append('\n');//添加一個(gè)換行符 m_pTcpSocket->write(str);}void QGuiTcpServer::onNewConnection(){ m_pTcpSocket = m_pTcpServer->nextPendingConnection(); //創(chuàng)建socket connect(m_pTcpSocket, SIGNAL(connected()), this, SLOT(onClientConnected())); onClientConnected(); connect(m_pTcpSocket, SIGNAL(disconnected()), this, SLOT(onClientDisconnected())); connect(m_pTcpSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChange(QAbstractSocket::SocketState))); onSocketStateChange(m_pTcpSocket->state()); connect(m_pTcpSocket, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead()));}void QGuiTcpServer::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"); }}//客戶端接入時(shí)void QGuiTcpServer::onClientConnected(){ ui.plainTextEdit->appendPlainText("**client socket connected"); ui.plainTextEdit->appendPlainText("**peer address:" + m_pTcpSocket->peerAddress().toString()); ui.plainTextEdit->appendPlainText("**peer port:" + QString::number(m_pTcpSocket->peerPort()));}//客戶端斷開連接時(shí)void QGuiTcpServer::onClientDisconnected(){ ui.plainTextEdit->appendPlainText("**client socket disconnected"); m_pTcpSocket->deleteLater();}//讀取緩沖區(qū)行文本void QGuiTcpServer::onSocketReadyRead(){ while (m_pTcpSocket->canReadLine()) ui.plainTextEdit->appendPlainText("[in] " + m_pTcpSocket->readLine());}//關(guān)閉窗口時(shí)停止監(jiān)聽void QGuiTcpServer::closeEvent(QCloseEvent* event){ if (m_pTcpServer->isListening()) m_pTcpServer->close();;//停止網(wǎng)絡(luò)監(jiān)聽 event->accept();}//獲取本機(jī)IP地址QString QGuiTcpServer::getLocalIP(){ QString hostName = QHostInfo::localHostName();//本機(jī)主機(jī)名 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;}TCPClient程序程序具有如下的功能:
?? ??通過IP地址和端口號(hào)連接到服務(wù)器;?
?? ??采用基于行的數(shù)據(jù)通信協(xié)議,與服務(wù)器端收發(fā)消息:?
?? ??處理QTcpSocket的StateChange()信號(hào),在狀態(tài)欄顯示socket的狀態(tài)。
頭文件
#pragma once#include #include "ui_QGuiTcpClient.h"#include #include class QGuiTcpClient : public QMainWindow{ Q_OBJECTpublic: QGuiTcpClient(QWidget *parent = Q_NULLPTR); ~QGuiTcpClient();private slots: //自定義槽函數(shù) void onConnected(); void onDisconnected(); void onSocketStateChange(QAbstractSocket::SocketState socketState); void onSocketReadyRead();//讀取socket傳入的數(shù)據(jù) void actConnect_triggered(); void actDisconnect_triggered(); void actClear_triggered(); void btnSend_clicked();private: Ui::QGuiTcpClient ui;protected: void closeEvent(QCloseEvent* event);private: QTcpSocket* m_pTcpClient; //socket QLabel* m_pLabSocketState;//狀態(tài)欄標(biāo)簽 QString getLocalIP();//獲取本機(jī)IP地址};源文件
#include "QGuiTcpClient.h"#include #include #pragma execution_character_set("utf-8")QGuiTcpClient::QGuiTcpClient(QWidget* parent) : QMainWindow(parent){ ui.setupUi(this); m_pTcpClient = new QTcpSocket(this); //創(chuàng)建socket變量 m_pLabSocketState = new QLabel("Socket狀態(tài):");//狀態(tài)欄標(biāo)簽 m_pLabSocketState->setMinimumWidth(250); ui.statusBar->addWidget(m_pLabSocketState); QString localIP = getLocalIP();//本機(jī)IP this->setWindowTitle(this->windowTitle() + "----本機(jī)IP:" + localIP); ui.comboServer->addItem(localIP); connect(m_pTcpClient, SIGNAL(connected()), this, SLOT(onConnected())); connect(m_pTcpClient, SIGNAL(disconnected()), this, SLOT(onDisconnected())); connect(m_pTcpClient, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(onSocketStateChange(QAbstractSocket::SocketState))); connect(m_pTcpClient, SIGNAL(readyRead()), this, SLOT(onSocketReadyRead())); connect(ui.actConnect, SIGNAL(triggered()), this, SLOT(actConnect_triggered())); connect(ui.actDisconnect, SIGNAL(triggered()), this, SLOT(actDisconnect_triggered())); connect(ui.actClear, SIGNAL(triggered()), this, SLOT(actClear_triggered())); connect(ui.btnSend, SIGNAL(clicked()), this, SLOT(btnSend_clicked()));}QGuiTcpClient::~QGuiTcpClient(){}void QGuiTcpClient::onConnected(){ ui.plainTextEdit->appendPlainText("**已連接到服務(wù)器"); ui.plainTextEdit->appendPlainText("**peer address:" + m_pTcpClient->peerAddress().toString()); ui.plainTextEdit->appendPlainText("**peer port:" + QString::number(m_pTcpClient->peerPort())); ui.actConnect->setEnabled(false); ui.actDisconnect->setEnabled(true);}void QGuiTcpClient::onDisconnected(){ ui.plainTextEdit->appendPlainText("**已斷開與服務(wù)器的連接"); ui.actConnect->setEnabled(true); ui.actDisconnect->setEnabled(false);}void QGuiTcpClient::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"); }}void QGuiTcpClient::onSocketReadyRead(){ while (m_pTcpClient->canReadLine()) ui.plainTextEdit->appendPlainText("[in] " + m_pTcpClient->readLine());}void QGuiTcpClient::actConnect_triggered(){ QString addr = ui.comboServer->currentText(); quint16 port = ui.spinPort->value(); m_pTcpClient->connectToHost(addr, port);}void QGuiTcpClient::actDisconnect_triggered(){ if (m_pTcpClient->state() == QAbstractSocket::ConnectedState) m_pTcpClient->disconnectFromHost();}void QGuiTcpClient::actClear_triggered(){ ui.plainTextEdit->clear();}void QGuiTcpClient::btnSend_clicked(){ QString msg = ui.editMsg->text(); ui.plainTextEdit->appendPlainText("[out] " + msg); ui.editMsg->clear(); ui.editMsg->setFocus(); QByteArray str = msg.toUtf8(); str.append('\n'); m_pTcpClient->write(str);}void QGuiTcpClient::closeEvent(QCloseEvent* event){ if (m_pTcpClient->state() == QAbstractSocket::ConnectedState) m_pTcpClient->disconnectFromHost(); event->accept();}QString QGuiTcpClient::getLocalIP(){ QString hostName = QHostInfo::localHostName();//本地主機(jī)名 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 tcp通信_Qt之网络编程TCP通信的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: android蓝牙固件升级_AirPod
- 下一篇: 判定重大风险有哪几种_化工生产安全管理信