一、TCP通信框架
二、QT中的服務(wù)器操作
- 創(chuàng)建一個(gè)QTcpServer類對(duì)象,該類對(duì)象就是一個(gè)服務(wù)器
- 調(diào)用listen函數(shù)將該對(duì)象設(shè)置為被動(dòng)監(jiān)聽狀態(tài),監(jiān)聽時(shí),可以監(jiān)聽指定的ip地址,也可以監(jiān)聽所有主機(jī)地址,可以通過指定端口號(hào),也可以讓服務(wù)器自動(dòng)選擇
- 當(dāng)有客戶端發(fā)來連接請(qǐng)求時(shí),該服務(wù)器會(huì)自動(dòng)發(fā)射一個(gè)newConnection信號(hào),我們可以將該信號(hào)連接到自定義槽函數(shù)處理相關(guān)邏輯
- 在槽函數(shù)中,可以調(diào)用nextPendingConnection函數(shù)可以獲得最新連接的客戶端套接字地址,我們可以將該套接字地址存儲(chǔ)到容器中
- 此時(shí)服務(wù)器與客戶端已經(jīng)建立連接,如果有客戶端向服務(wù)器發(fā)來數(shù)據(jù),那么對(duì)應(yīng)的客戶端套接字就會(huì)發(fā)射一個(gè)readyRead信號(hào)
- 讀取套接字中的數(shù)據(jù)使用read、readLine、readAll函數(shù)來完成
- 向套接字中寫數(shù)據(jù),可以使用write
- 關(guān)閉服務(wù)器,使用close來完成
Server界面代碼:
系統(tǒng)管理文件:
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
?頭文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpServer> //服務(wù)器頭文件
#include <QTcpSocket> //客戶端頭文件
#include <QList> //鏈表頭文件用來存放客戶端容器
#include <QDebug>
#include <QMessageBox> //消息對(duì)話框
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_clicked();
void newConnection_slot();
void readyRead_slot(); //自定義處理readyRead信號(hào)的槽函數(shù)
private:
Ui::Widget *ui;
//定義服務(wù)器指針
QTcpServer *server;
//定義客戶端指針鏈表容器
QList<QTcpSocket *> clientList;
};
#endif // WIDGET_H
主函數(shù):
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
主要功能函數(shù):
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//給服務(wù)器指針實(shí)例化對(duì)象
server = new QTcpServer(this); //服務(wù)器創(chuàng)建完成
}
Widget::~Widget()
{
delete ui;
}
//啟動(dòng)服務(wù)器按鈕對(duì)應(yīng)的槽函數(shù)
void Widget::on_pushButton_clicked()
{
//獲取UI界面的端口號(hào)
quint16 port = ui->lineEdit->text().toUInt();
//將服務(wù)器設(shè)置為被動(dòng)監(jiān)聽狀態(tài)
//bool QTcpServer::listen(const QHostAddress &address = QHostAddress::Any, quint16 port = 0)
//參數(shù)1:要監(jiān)聽的主機(jī)地址,如果是any,表示監(jiān)聽所有主機(jī)地址,也可以給特定的主機(jī)地址進(jìn)行監(jiān)聽
//參數(shù)2:通過指定的端口號(hào)進(jìn)行訪問服務(wù)器,如果是0,表示由服務(wù)器自動(dòng)分配。如果非0,則表示指定端口號(hào)
//返回值:成功返回真,失敗返回假
if(!server->listen(QHostAddress::Any,port))
{
QMessageBox::critical(this, "失敗", "服務(wù)器啟動(dòng)失敗");
}else{
QMessageBox::information(this, "成功", "服務(wù)器啟動(dòng)成功");
}
//執(zhí)行到這表明服務(wù)器啟動(dòng)成功,并對(duì)客戶端連接進(jìn)行監(jiān)聽,如果有客戶端向服務(wù)器發(fā)來連接請(qǐng)求,那么該服務(wù)器就會(huì)自動(dòng)發(fā)射一個(gè)newConnection信號(hào)
//我們可以將信號(hào)連接到對(duì)應(yīng)的槽函數(shù)中處理相關(guān)邏輯
connect(server, &QTcpServer::newConnection, this, &Widget::newConnection_slot);
}
void Widget::newConnection_slot()
{
qDebug() <<"有客戶端申請(qǐng)連接";
//獲取最新連接的客戶端套接字
//[virtual] QTcpSocket *QTcpServer::nextPendingConnection()
QTcpSocket *s = server->nextPendingConnection();
//將獲取的套接字存放到客戶端容器中
clientList.push_back(s);
//此時(shí),客戶端就和服務(wù)器建立起來聯(lián)系了
//如果客戶端有數(shù)據(jù)向服務(wù)器發(fā)送過來,那么該套接字就會(huì)自動(dòng)發(fā)送一個(gè)readyread信號(hào)
//我們可以將該信號(hào)連接到自定義的槽函數(shù)中處理相關(guān)邏輯
connect(s, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
}
//關(guān)于readyRead信號(hào)對(duì)應(yīng)槽函數(shù)的實(shí)現(xiàn)
void Widget::readyRead_slot()
{
//刪除客戶端鏈表中的無效客戶端套接字
for(int i=0; i<clientList.count(); i++)
{
//判斷套接字的狀態(tài)
//函數(shù)原型 SocketState state() const;
//功能:返回客戶端狀態(tài)
//返回值:客戶端狀態(tài),如果是0,表示無連接
if(clientList[i]->state() == 0)
{
clientList.removeAt(i); //將下標(biāo)為i的客戶端移除
}
}
//遍歷所有客戶端,查看是哪個(gè)客戶端發(fā)來數(shù)據(jù)
for(int i=0; i<clientList.count(); i++)
{
//函數(shù)原型:qint64 bytesAvailable() const override;
//功能:返回當(dāng)前客戶端套接字中的可讀數(shù)據(jù)字節(jié)個(gè)數(shù)
//返回值:當(dāng)前客戶端待讀的字節(jié)數(shù),如果該數(shù)據(jù)0,表示無待讀數(shù)據(jù)
if(clientList[i]->bytesAvailable() != 0)
{
//讀取當(dāng)前客戶端的相關(guān)數(shù)據(jù)
//函數(shù)原型:QByteArray readAll();
//功能:讀取當(dāng)前套接字中的所有數(shù)據(jù),并返回一個(gè)字節(jié)數(shù)組
//返回值:數(shù)據(jù)的字節(jié)數(shù)組
QByteArray msg = clientList[i]->readAll();
//將數(shù)據(jù)戰(zhàn)術(shù)到ui界面上
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
//將接收到的該消息,發(fā)送給所有客戶端
for(int j=0; j<clientList.count(); j++)
{
clientList[j]->write(msg);
}
}
}
}
所用組件:
?三、QT中的客戶端操作
- 實(shí)例化一個(gè)QTcpSocket類對(duì)象
- 調(diào)用該對(duì)象的成員函數(shù)connectToHost連接到服務(wù)器,連接服務(wù)器時(shí),需要給定服務(wù)器的ip地址和端口號(hào)
- 如果連接服務(wù)器成功,那么該客戶端就會(huì)自動(dòng)發(fā)送一個(gè)connected信號(hào),我們可以將該信號(hào)連接到自定義槽函數(shù)中處理相關(guān)邏輯
- 如果服務(wù)器向客戶端發(fā)來數(shù)據(jù),那么該客戶端就會(huì)自動(dòng)發(fā)射一個(gè)readyRead信號(hào),我們可以將該信號(hào)連接到自定義的槽函數(shù)中處理相關(guān)邏輯
- 可以使用read、readLine、readAll讀取客戶端中的數(shù)據(jù)
- 可以使用write向服務(wù)器發(fā)送數(shù)據(jù)
- 使用成員函數(shù)disConnectFromHost斷開與服務(wù)器的連接
- 如果成功斷開與服務(wù)器的連接,那么該套接字就會(huì)自動(dòng)發(fā)射一個(gè)disconn信號(hào)
Client界面代碼:
?系統(tǒng)管理文件:
QT += core gui network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++11
# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
widget.cpp
HEADERS += \
widget.h
FORMS += \
widget.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
?頭文件:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpSocket>
#include <QMessageBox>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
void on_pushButton_2_clicked();
void connected_slot(); //自定義處理信號(hào)的槽函數(shù)
void readyRead_slot(); //自定義處理readyRead信號(hào)的槽函數(shù)
void disconnected_slot(); //自定義處理disconnected信號(hào)的槽函數(shù)
void on_pushButton_clicked();
void on_pushButton_3_clicked();
private:
Ui::Widget *ui;
//定義一個(gè)客戶端指針
QTcpSocket *socket;
//用戶名
QString userName;
};
#endif // WIDGET_H
主函數(shù):
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
主要功能函數(shù):
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//給客戶端指針實(shí)例化空間
socket = new QTcpSocket(this);
//如果連接服務(wù)器成功,該客戶端就會(huì)發(fā)射一個(gè)connected信號(hào)
//我們可以將該信號(hào)連接到自定義的槽函數(shù)中處理相關(guān)邏輯
//由于該連接只需要連接一次。所有在構(gòu)造函數(shù)中即可
connect(socket, &QTcpSocket::connected, this, &Widget::connected_slot);
//客戶端與服務(wù)器連接成功后,如果服務(wù)器向客戶端發(fā)來數(shù)據(jù),那么該客戶端就會(huì)自動(dòng)發(fā)射一個(gè)readyRead信號(hào)
//我們可以將該信號(hào)連接到自定義槽函數(shù)中處理相關(guān)邏輯
connect(socket, &QTcpSocket::readyRead, this, &Widget::readyRead_slot);
//當(dāng)客戶端與服務(wù)器斷開連接后,該客戶端就會(huì)自動(dòng)發(fā)射1一個(gè)disconnected信號(hào)
//我們可以將該信號(hào)與自定義的槽函數(shù)連接
//由于只需要連接一下,所有該連接寫到構(gòu)造函數(shù)即可
connect(socket, &QTcpSocket::disconnected, this, &Widget::disconnected_slot);
}
Widget::~Widget()
{
delete ui;
}
//連接服務(wù)器按鈕對(duì)應(yīng)的槽函數(shù)
void Widget::on_pushButton_2_clicked()
{
//獲取UI界面的信息
userName = ui->lineEdit_2->text(); //獲取用戶名
QString hostName = ui->lineEdit_3->text(); //獲取主機(jī)地址
quint16 port = ui->lineEdit_4->text().toUInt(); //獲取端口號(hào)
//調(diào)用函數(shù)連接到主機(jī)
//函數(shù)原型:[virtual] void QAbstractSocket::connectToHost(const QString &hostName, quint16 port)
//參數(shù)1:服務(wù)器的主機(jī)地址
//參數(shù)2:端口號(hào)
//返回值:無
socket->connectToHost(hostName,port);
}
//關(guān)于處理connected信號(hào)的槽函數(shù)
void Widget::connected_slot()
{
QMessageBox::information(this,"成功","連接服務(wù)器成功");
//順便向服務(wù)器發(fā)送一條消息,說:xxx進(jìn)入聊天室
QString msg = userName + "進(jìn)入聊天室";
socket->write(msg.toLocal8Bit());
}
//關(guān)于readyRead信號(hào)對(duì)應(yīng)槽函數(shù)的實(shí)現(xiàn)
void Widget::readyRead_slot()
{
//讀取該客戶端中的數(shù)據(jù)
//返回值:QBytearray
QByteArray msg = socket->readAll();
//將數(shù)據(jù)展示在UI界面
ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}
void Widget::on_pushButton_clicked()
{
//獲取UI界面中的編輯的文本內(nèi)容
QString m = ui->lineEdit->text();
//整合要發(fā)送的信息
QString msg = userName + ": " + m;
//將消息發(fā)送給服務(wù)器
socket->write(msg.toLocal8Bit());
//將消息編輯框中的內(nèi)容清空
ui->lineEdit->clear();
}
//斷開服務(wù)器按鈕對(duì)應(yīng)的槽函數(shù)
void Widget::on_pushButton_3_clicked()
{
//準(zhǔn)備要發(fā)送的信息
QString msg = userName + ": 離開聊天室";
socket->write(msg.toLocal8Bit());
//調(diào)用成員函數(shù)disconnectFromHost
//函數(shù)原型:virtual void disconnectFromHost();
//功能:斷開服務(wù)器與客戶端的連接
//參數(shù):無
//返回值:無
socket->disconnectFromHost();
}
//disconn信號(hào)對(duì)應(yīng)槽函數(shù)的實(shí)現(xiàn)
void Widget::disconnected_slot()
{
QMessageBox::information(this, "退出", "斷開成功");
}
?所用組件:文章來源:http://www.zghlxwxcb.cn/news/detail-706991.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-706991.html
到了這里,關(guān)于QT實(shí)現(xiàn)TCP通信(服務(wù)器與客戶端搭建)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!