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