基于QT制作一個(gè)TCPServer與TCPClient的通信
前言
之前項(xiàng)目上用到了TCP通信,作為TCP的服務(wù)端上位機(jī)與下位機(jī)進(jìn)行控制信號(hào)傳輸。
這篇博客就對(duì)QT中使用TCP通信理一個(gè)簡(jiǎn)單的demo,做一個(gè)簡(jiǎn)單的TCP服務(wù)端和客戶端的通信。
因?yàn)闀r(shí)間有限,這里就闡述一下基本原理和代碼實(shí)現(xiàn),具體的demo參考的是《QT5.9C++開發(fā)指南》
具體效果圖如下

1. TCP通信原理和流程闡述
1.1 TCP 通信原理簡(jiǎn)述
TCP通信主要是三次握手和四次揮手,前者是建立連接,后者是斷開連接。

上圖是三次握手的一個(gè)基本流程圖:
首先客戶機(jī)向服務(wù)器申請(qǐng)同步,即向服務(wù)器申請(qǐng)連接。
服務(wù)器接收到請(qǐng)求,返回一個(gè)確認(rèn)幀,告訴客戶機(jī)已經(jīng)收到你的請(qǐng)求,同意連接。
客戶機(jī)收到同意請(qǐng)求信息之后,還要告訴服務(wù)器它已經(jīng)收到服務(wù)器的確認(rèn)請(qǐng)求,接下來可以傳輸數(shù)據(jù)。
上面是一個(gè)簡(jiǎn)單的TCP建立連接的闡述,那么回歸到服務(wù)器端。在QT中,TCP服務(wù)器端使用QTcpServer用于端口監(jiān)聽和建立服務(wù)器,服務(wù)器和客戶端之間在建立連接后,通信使用QTcpSocket,套接字Socket進(jìn)行。
1.2 TCP服務(wù)端建立與通信流程
在QT中,使用QTcpServer::listen()函數(shù)開始服務(wù)器端監(jiān)聽,這里可以指定監(jiān)聽的IP地址和端口。這個(gè)表示服務(wù)器的IP和端口,監(jiān)聽向這個(gè)IP和端口發(fā)起請(qǐng)求的客戶端。
當(dāng)有新的客戶端接入時(shí),QTcpServer內(nèi)部的incomingConnection()函數(shù)會(huì)創(chuàng)建一個(gè)與客戶端連接的QTcpSocket對(duì)象,接著發(fā)射信號(hào)newConnection()。在newConnection()信號(hào)的槽函數(shù)中,可以用nextPendingConnection()接收客戶端的連接,最后使用QTcpSocket與客戶端通信。
1.3 TCP客戶端通信流程
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ù)。
2. 關(guān)鍵源碼闡述
2.1 服務(wù)端代碼
初始化TCP服務(wù)端,綁定信號(hào)與槽函數(shù)
QTcpServer *tcpServer; //TCP服務(wù)器
QTcpSocket *tcpSocket;//TCP通訊的Socket
tcpServer=new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
定義了一個(gè)TcpServer的對(duì)象tcpServer,將獲取的newConnection()信號(hào)綁定到自定義的槽函數(shù)onNewConnection()上。
開始監(jiān)聽,選擇IP和端口號(hào)
void MainWindow::on_actStart_triggered()
{//開始監(jiān)聽
QString IP=ui->comboIP->currentText();//IP地址
quint16 port=ui->spinPort->value();//端口
QHostAddress addr(IP);
tcpServer->listen(addr,port);//指定ip和端口,這里的IP就是默認(rèn)IP端口也是控件的默認(rèn)值端口
// tcpServer->listen(QHostAddress::LocalHost,port);// Equivalent to QHostAddress("127.0.0.1").
...
...
}
下面這個(gè)函數(shù)綁定了一些tcp連接的狀態(tài)信號(hào)和對(duì)應(yīng)的處理函數(shù)。
對(duì)于接收到的tcpServer連接,使用nextPending函數(shù)創(chuàng)建socket進(jìn)行通信。
void MainWindow::onNewConnection()
{
// ui->plainTextEdit->appendPlainText("有新連接");
tcpSocket = tcpServer->nextPendingConnection(); //創(chuàng)建socket
connect(tcpSocket, SIGNAL(connected()),
this, SLOT(onClientConnected()));
onClientConnected();//
connect(tcpSocket, SIGNAL(disconnected()),
this, SLOT(onClientDisconnected()));
connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
onSocketStateChange(tcpSocket->state());
connect(tcpSocket,SIGNAL(readyRead()),
this,SLOT(onSocketReadyRead()));
}
服務(wù)端發(fā)送數(shù)據(jù)函數(shù):
void MainWindow::on_btnSend_clicked()
{//發(fā)送一行字符串,以換行符結(jié)束
QString msg=ui->editMsg->text();
ui->plainTextEdit->appendPlainText("[out] "+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
QByteArray str=msg.toUtf8();
str.append('\n');//添加一個(gè)換行符
tcpSocket->write(str);
}
服務(wù)器讀取數(shù)據(jù)
void MainWindow::onSocketReadyRead()
{//讀取緩沖區(qū)行文本
// QStringList lines;
while(tcpSocket->canReadLine())
ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
// lines.append(clientConnection->readLine());
}
2.2 客戶端代碼
對(duì)于客戶端來說主要是socket通信
初始化客戶端并綁定信號(hào)
QTcpSocket *tcpClient; //socket
tcpClient=new QTcpSocket(this); //創(chuàng)建socket變量
connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnected()));
connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
connect(tcpClient,SIGNAL(readyRead()),
this,SLOT(onSocketReadyRead()));
連接到服務(wù)器
QString addr=ui->comboServer->currentText();
quint16 port=ui->spinPort->value();
tcpClient->connectToHost(addr,port);
發(fā)送數(shù)據(jù)
void MainWindow::on_btnSend_clicked()
{//發(fā)送數(shù)據(jù)
QString msg=ui->editMsg->text();
ui->plainTextEdit->appendPlainText("[out] "+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
QByteArray str=msg.toUtf8();
str.append('\n');
tcpClient->write(str);
}
讀取數(shù)據(jù)
void MainWindow::onSocketReadyRead()
{//readyRead()信號(hào)槽函數(shù)
while(tcpClient->canReadLine())
ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readLine());
}以上就是基于QT制作一個(gè)TCPServer與TCPClient的通信的詳細(xì)內(nèi)容,更多關(guān)于QT TCP通信的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C語(yǔ)言Iniparser庫(kù)實(shí)現(xiàn)ini文件讀寫
iniparser是針對(duì)INI文件的解析器。ini文件則是一些系統(tǒng)或者軟件的配置文件。本文就來介紹一下如何利用Iniparser庫(kù)實(shí)現(xiàn)ini文件讀寫吧2023-03-03
C++類與對(duì)象深入之靜態(tài)成員與友元及內(nèi)部類詳解
朋友們好,這篇播客我們繼續(xù)C++的初階學(xué)習(xí),現(xiàn)在對(duì)我們對(duì)C++的靜態(tài)成員,友元,內(nèi)部類知識(shí)點(diǎn)做出總結(jié),整理出來一篇博客供我們一起復(fù)習(xí)和學(xué)習(xí),如果文章中有理解不當(dāng)?shù)牡胤?還希望朋友們?cè)谠u(píng)論區(qū)指出,我們相互學(xué)習(xí),共同進(jìn)步2022-06-06
C語(yǔ)言實(shí)現(xiàn)二叉樹鏈?zhǔn)浇Y(jié)構(gòu)的示例詳解
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)二叉樹鏈?zhǔn)浇Y(jié)構(gòu)的相關(guān)資料,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C語(yǔ)言有一定的幫助,需要的可以參考一下2022-11-11
C語(yǔ)言實(shí)現(xiàn)靜態(tài)鏈表的方法
分享一段代碼,一個(gè)靜態(tài)鏈表的C語(yǔ)言實(shí)現(xiàn),其中包含著一種簡(jiǎn)單的內(nèi)存管理策略:固定大小的鏈?zhǔn)焦芾怼?/div> 2013-03-03
Qt?QDateTime計(jì)算時(shí)間差的實(shí)現(xiàn)示例
本文主要介紹了Qt?QDateTime計(jì)算時(shí)間差的實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-04-04
MFC實(shí)現(xiàn)簡(jiǎn)單計(jì)算器
這篇文章主要為大家詳細(xì)介紹了MFC實(shí)現(xiàn)簡(jiǎn)單的計(jì)算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05
C語(yǔ)言實(shí)現(xiàn)單詞小助手功能完善版
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)單詞小助手功能的完善版,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10最新評(píng)論

