Qt系统相关
- 一、Qt网络
-
- [1、UDP Socket](#1、UDP Socket)
- [2、TCP Socket](#2、TCP Socket)
- [3、HTTP Client](#3、HTTP Client)
一、Qt网络
在进行网络编程之前,需要在项目中的.pro文件中添加network模块
实际开发中不会用Qt直接写服务器的,因为服务器是没有图形化界面的,一般我们会用其他的语言软件写好程序之后与Qt联合使用,这里只是演示
在实现网络编程的时候在pro文件中要加入network
1、UDP Socket
(1)核心API
方法 | 说明 |
---|---|
bind(const QHostAddress&,quint16) | 绑定指定的端口号 |
receiveDatagram | 返回QNetworkDatagram,读取一个UDP数据报 |
writeDatagram(const QNetworkDatagram&) | 发送一个UDP数据报 |
信号 | 说明 |
---|---|
readyRead | 在收到数据并准备就绪后触发 |
QNetworkDatagram
构造函数 | 说明 |
---|---|
QNetworkDatagram(const QByteArray& ,const QHostAddress& ,quint16) | 通过QByteArray,目标IP地址,目标端口号构造一个UDP数据报 |
方法 | 说明 |
---|---|
data | 获取数据报内部持有的数据,返回QByteArray |
senderAddress | 获取数据报中包含的对端的IP地址 |
senderPort | 获取数据报中包含的对端的端口号 |
(2)回显服务器
回显服务器和回显客户端顾名思义就是我给服务器发送什么服务器给我发送什么
widget.cpp
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//修改窗口标题
this->setWindowTitle("服务器");
//创建udp实例
socket = new QUdpSocket(this);
//连接信号槽
connect(socket,&QUdpSocket::readyRead,this,&Widget::processRequest);
//绑定端口
bool ret = socket->bind(QHostAddress::Any,9090);
if(!ret)
{
QMessageBox::critical(nullptr,"服务器启动有误",socket->errorString());
return;
}
}
void Widget::processRequest()
{
//读取请求
const QNetworkDatagram& requestDatagram = socket->receiveDatagram();
//解析请求
QString request = requestDatagram.data();
//根据请求计算响应
const QString& response = process(request);
//响应回写客户端
QNetworkDatagram responseDatagram(response.toUtf8(),requestDatagram.senderAddress(),requestDatagram.senderPort());
socket->writeDatagram(responseDatagram);
//交互信息显示到窗口上
QString log = "[" + requestDatagram.senderAddress().toString() + ":" + QString::number(requestDatagram.senderPort())+"}req: "+request+",resp:"+response;
ui->listWidget->addItem(log);
}
QString Widget::process(const QString &request)
{
//对于回显服务器来说,请求就是回应,但是对于大型的商务服务器,这里的代码量是非常巨大的
return request;
}
(3)回显客户端
widget.cpp
cpp
const QString& SERVER_IP = "127.0.0.1";//客户端IP地址
const quint16 SERVER_PORT = 9090;//客户端端口号
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//实例
socket = new QUdpSocket(this);
//窗口名
this->setWindowTitle("客户端");
//信号槽连接
connect(socket,&QUdpSocket::readyRead,this,&Widget::processResponse);
}
//这个函数用来处理收到的响应
void Widget::processResponse()
{
//读取解析响应
const QNetworkDatagram& responseDatagram = socket->receiveDatagram();
QString response = responseDatagram.data();
//因为是回显服务器,直接将响应数据显示到界面上
ui->listWidget->addItem("服务器:"+response);
}
void Widget::on_pushButton_clicked()
{
//获取到输入框的内容
const QString& text = ui->lineEdit->text();
//构造请求数据
QNetworkDatagram requestDatagram(text.toUtf8(),QHostAddress(SERVER_IP),SERVER_PORT);
//发送请求数据
socket->writeDatagram(requestDatagram);
//发送的请求添加到列表框
ui->listWidget->addItem("客户端:"+text);
//清空输入框内容
ui->lineEdit->setText("");
}
qudpsocket
2、TCP Socket
(1)核心API
主要有两个核心类
QTcpServer
方法 | 说明 |
---|---|
listen(const QHostAddress&,quint16 port) | 绑定指定的地址和端口号,并开始监听 |
nextPendingConnection | 从系统中获取到一个已经建立好的tcp连接,返回一个QTcpSocket,表示这个客户端的连接,通过这个socket对象完成和客户端之间的通信 |
信号 | 说明 |
---|---|
newConnection | 有新的客户端建立好之后触发 |
QTcpSocket
方法 | 说明 |
---|---|
readAll | 读取当前接收缓冲区中的所有数据并返回一个QByteArray对象 |
write(const QByteArray&) | 把数据写入socket中 |
deleteLater | 暂时把socket对象标记为无效,Qt会在下个事件循环中析构释放该对象 |
信号 | 说明 |
---|---|
readyRead | 有数据到达准备就绪时触发 |
disconnected | 断开连接时触发 |
(2)回显服务器
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 1. 修改窗口标题.
this->setWindowTitle("服务器");
// 2. 创建 QTcpServer 的实例
tcpServer = new QTcpServer(this);
// 3. 通过信号槽, 指定如何处理连接.
connect(tcpServer, &QTcpServer::newConnection, this, &Widget::processConnection);
// 4. 绑定并监听端口号. 一定要确保准备工作充分了, 再真正开张营业.
// 这个操作得是初始化的最后一步. 都是需要把如何处理连接, 如何处理请求... 都准备好之后, 才能真正绑定端口并监听.
bool ret = tcpServer->listen(QHostAddress::Any, 9090);
if (!ret) {
QMessageBox::critical(this, "服务器启动失败!", tcpServer->errorString());
exit(1);
}
}
Widget::~Widget()
{
delete ui;
}
void Widget::processConnection()
{
//通过tcpServer获得socket对象, 通过这个对象来和客户端进行通信
QTcpSocket* clientSocket = tcpServer->nextPendingConnection();
QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] 客户端上线!";
ui->listWidget->addItem(log);
//通过信号槽, 来处理客户端发来请求的情况
connect(clientSocket, &QTcpSocket::readyRead, this, [=]() {
//读取出请求数据. 此处 readAll 返回的是 QByteArray, 通过赋值转成 QString
QString request = clientSocket->readAll();
//根据请求处理响应
const QString& response = process(request);
//把响应写回到客户端
clientSocket->write(response.toUtf8());
//把上述信息记录到日志中
QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] "
+ " req: " + request + ", resp: " + response;
ui->listWidget->addItem(log);
});
//通过信号槽处理客户端断开连接情况
connect(clientSocket, &QTcpSocket::disconnected, this, [=]() {
//断开连接信息通过日志打印
QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "] 客户端下线!";
ui->listWidget->addItem(log);
//手动释放 clientSocket. 使用deleteLater更加合适
clientSocket->deleteLater();
});
}
//回显服务器.
QString Widget::process(const QString request)
{
return request;
}
(3)回显客户端
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//设置窗口标题
this->setWindowTitle("客户端");
//创建socket实例
socket = new QTcpSocket(this);
//和服务器连接
socket->connectToHost("127.0.0.1", 9090);
//连接信号槽, 处理响应
connect(socket, &QTcpSocket::readyRead, [=]() {
// 读取出响应内容
QString response = socket->readAll();
// 把响应内容显示到界面上
ui->listWidget->addItem("服务器说: " + response);
});
// 等待连接建立的结果. 确认是否连接成功
bool ret = socket->waitForConnected();
if (!ret) {
QMessageBox::critical(this, "连接服务器出错", socket->errorString());
exit(1);
}
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
// 获取到输入框中的内容
const QString& text = ui->lineEdit->text();
// 发送数据给服务器
socket->write(text.toUtf8());
// 把发的消息显示到界面上
ui->listWidget->addItem("客户端说: " + text);
// 清空输入框的内容
ui->lineEdit->setText("");
}
qtcpsocket
3、HTTP Client
QNetworkAccessManager
提供核心操作
方法 | 说明 |
---|---|
get(const QNetworkRequest& ) | 发起一个HTTP GET请求,返回QNetworkReply对象 |
post(const QNetworkRequest& ,const QByteArray& ) | 发起一个HTTP POST请求,返回QNetworkReply对象 |
QNetworkRequest
表示一个HTTP请求,不含body,body是数据本体
方法 | 说明 |
---|---|
QNetworkRequest(const QUrl& ) | 通过URL构造一个HTTP请求 |
setHeader(QNetworkRequest::KnowHeaders header,const QVariant& value) | 设置请求头 |
QNetworkReply
方法 | 说明 |
---|---|
error | 获取出错状态 |
errorString | 获取出错原因的文本 |
readAll | 读取响应body |
header(QNetworkRequest::KnownHeaders header) | 读取相应指定header的值 |
cpp
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
manager = new QNetworkAccessManager(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//获取到输⼊框中的URL, 构造QUrl对象
QUrl url(ui->lineEdit->text());
//构造HTTP请求对象
QNetworkRequest request(url);
//发送GET请求
QNetworkReply* response = manager->get(request);
//通过信号槽来处理响应
connect(response, &QNetworkReply::finished, this, [=]() {
if (response->error() == QNetworkReply::NoError)
{
//响应正确
QString html(response->readAll());
ui->plainTextEdit->setPlainText(html);
}
else
{
//响应出错
ui->plainTextEdit->setPlainText(response->errorString());
}
response->deleteLater();
});
}
qhttp
今日分享就到这里了~