目录
一、概述
在Qt中,网络编程使用Qt网络模块来实现。对网络编程的API也进行了重新封装。 提供了一套高级的网络编程接口,可以方便地进行网络通信。
在进行网络编程之前,需要在项目中的.pro文件中添加network 模块. 添加之后要 手动编译一下项目, 使Qt Creator能够加载对应模块的头文件.
Qt中的网络模块就是封装了网络API,可参考网络模块,点此处跳转
二、UDP
Qt中的UDP是指用户数据报协议(User Datagram Protocol),它是一种无连接的传输协议,用于在网络上发送数据。在Qt中,可以使用QUdpSocket类来实现UDP通信。
QUdpSocket类提供了用于创建和管理UDP套接字的方法,可以用于发送和接收UDP数据报。
主要的类有两个. QUdpSocket和QNetworkDatagram
QUdpSocket表示一个UDP的socket文件.
QNetworkDatagram 表示一个 UDP 数据报
实例
实现一个简易回显服务器
1.服务器搭建
创建项目,在.pro文件中添加network
在ui中拖入一个QlistWidget显示服务器收到的请求
编写代码
#include "widget.h"
#include "ui_widget.h"
#include<QUdpSocket>
#include<QMessageBox>
#include<QNetworkDatagram>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//创建对象 socket在类中声明
socket = new QUdpSocket(this);
//设置窗口标题
this->setWindowTitle("服务器");
//链接信号槽
connect(socket,&QUdpSocket::readyRead,this,&Widget::processRequest);
//绑定端口号
bool ret = socket->bind(QHostAddress::Any,8080);
if(!ret)
{
QMessageBox::critical(this,"服务器启动错误",socket->errorString());
return;
}
}
Widget::~Widget()
{
delete ui;
}
//请求处理接口
QString Widget::process(const QString &request)
{
//不做处理
return request;
}
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 +",rsp: "+response;
//将获取到的请求显示到控件中
ui->listWidget->addItem(log);
}
此时我们实现的是回显服务器,并不对服务器收到的请求做处理,在实际开发中,处理请求是特别核心的
2.客户端搭建
先在客户端的.pro文件中添加network
在ui中拖入三个控件,将三个控件按照合适的布局进行管理
#include "widget.h"
#include "ui_widget.h"
#include<QUdpSocket>
#include<QNetworkDatagram>
//服务器端地址和端口
const QString SERVER_IP ="127.0.0.1";
const quint16 PORT=8080;
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);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//获取输入框中内容
const QString& text = ui->lineEdit->text();
//构造UDP数据报
QNetworkDatagram requestDatagram(text.toUtf8(),QHostAddress(SERVER_IP),PORT);
//发送数据
socket->writeDatagram(requestDatagram);
//将发送的数据添加到列表框中
ui->listWidget->addItem("客户端:"+text);
ui->lineEdit->clear();
}
void Widget::processResponse()
{
//处理接收到的响应
const QNetworkDatagram& responseDatagram=socket->receiveDatagram();
QString response = responseDatagram.data();
//将服务器回应的数据显示到控件中
ui->listWidget->addItem("服务器:"+response);
}
注意,我们使用的是本地环回进行客户端与服务器通信
效果
三、TCP
在Qt中,可以使用QTcpSocket类和QTcpServer类来实现TCP通信。
QTcpSocket类是用于客户端的TCP套接字类,它允许Qt应用程序通过TCP协议与远程服务器进行通信。它提供了一些用于连接服务器、发送和接收数据的方法和信号。
QTcpServer类是用于服务器端的TCP服务类,它允许Qt应用程序在指定端口上监听并接受传入的TCP连接。一旦有连接建立,QTcpServer会创建一个QTcpSocket对象来处理该连接,并发出newConnection信号。
核心类是两个: QTcpServer 和 QTcpSocket
使用TCP套接字进行通信的一般步骤如下:
- 创建一个QTcpSocket对象或QTcpServer对象。
- 设置连接的服务器地址和端口(对于客户端)或指定监听的端口(对于服务器端)。
- 连接到服务器(对于客户端)或启动服务器(对于服务器端)。
- 对于客户端,可以使用connectToHost()方法连接到服务器;对于服务器端,可以使用listen()方法开始监听指定的端口。
- 一旦连接建立或有新的连接到来,会发出相应的信号(例如connected()信号、newConnection()信号)。
- 通过read()方法读取来自服务器的数据(对于客户端)或通过QTcpSocket对象的read()方法读取来自客户端的数据(对于服务器端)。
- 可以通过write()或writeData()方法向服务器发送数据(对于客户端)或通过QTcpSocket对象的write()或writeData()方法向客户端发送数据(对于服务器端)。
- 对于客户端,可以通过close()方法关闭连接或在读写过程中发生错误时自动关闭连接;对于服务器端,可以通过close()方法关闭服务器。
- 在不需要连接或服务器时,应当释放相应的QTcpSocket对象或QTcpServer对象。
QTcpServer用于监听端口,和获取客户端连接.
QTcpSocket用户客户端和服务器之间的数据交互.
QByteArray用于表示一个字节数组.可以很方便的和QString进行相互转换. 例如:
使用QString的构造函数即可把QByteArray转成QString.
使用QString的toUtf8函数即可把QString转成QByteArray.
实例
实现一个回显服务器和客户端
客户端与服务器界面搭建和UDP回显服务器一致,只是使用不同的步骤实现通信
服务器
通过信号方式处理连接,通过信号的方式处理断开连接,以及读取数据
#include "widget.h"
#include "ui_widget.h"
#include<QMessageBox>
#include<QTcpSocket>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//修改窗口标题
this->setWindowTitle("服务器");
tcpServer = new QTcpServer(this);
//通过信号槽,处理连接
connect(tcpServer,&QTcpServer::newConnection,this,&Widget::processConnecton);
//绑定并监听端口号
bool ret = tcpServer->listen(QHostAddress::Any,8080);
if(!ret)
{
QMessageBox::critical(this,"服务器启动失败",tcpServer->errorString());
exit(1);
}
}
Widget::~Widget()
{
delete ui;
}
QString Widget::process(const QString &request)
{
return request;
}
void Widget::processConnecton()
{
//通过tcpServer拿到socket对象,进行与客户端通信
QTcpSocket* clientsocket = tcpServer->nextPendingConnection();
QString log = "["+clientsocket->peerAddress().toString()+":"+QString::number(clientsocket->peerPort())+"]客户端上线";
ui->listWidget->addItem(log);
//通过信号槽,处理客户端请求
connect(clientsocket,&QTcpSocket::readyRead,this,[=](){
//读取请求数据
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 每个客户端有一个clientSocke,如果客户端连接过多,
//不会立即释放,
clientsocket->deleteLater();
});
}
客户端
#include "widget.h"
#include "ui_widget.h"
#include<QMessageBox>
#include<QListWidget>
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",8080);
//处理响应
connect(socket,&QTcpSocket::readyRead,this,[=](){
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->clear();
}
实现效果
四、HTTP
关键类主要是三个. QNetworkAccessManager,QNetworkRequest,QNe tworkReply
QNetworkAccessManager:
-
这是所有网络请求的核心管理器,负责处理HTTP、FTP等各种网络请求。
应用程序通常只需要创建一个QNetworkAccessManager实例,就可以处理所有的网络事务。
QNetworkRequest: -
这个类用于封装HTTP请求的细节,包括URL、HTTP头部信息(如Cookie、认证信息等)、请求方法(GET、POST等)等。
QNetworkReply:
- 当发出HTTP请求后,QNetworkAccessManager会返回一个QNetworkReply对象,它代表了HTTP响应。
- 通过信号槽机制,可以从QNetworkReply对象获取到服务器的响应数据、状态码、响应头等信息。
QNetworkReply
- 通常是异步工作的,这意味着发出请求后不会阻塞线程,而是在响应数据可用或请求完成时触发相应的信号。
QNetworkAccessManager提供了HTTP的核心操作
QNetworkRequest表示一个 HTTP请求(不含body).
如果需要发送一个带有body的请求(此如post),会在QNetworkAccessManager的post方法中通过单独的参数来传入body.
其中的QNetworkRequest: : KnownHeaders是一个枚举类型,常用取值:
QNetworkReply表示一个HTTP响应.这个类同时也是QIODevice的子类
QNetworkReply 还有一个重 要的信号finished 会在客户端收到完整的响应数据之后触发.
实例
简单搭建一个Http客户端
在ui中拖入一些控件
#include "widget.h"
#include "ui_widget.h"
#include<QNetworkReply>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("客户端");
//manager在.h中声明
manager= new QNetworkAccessManager(this);
}
Widget::~Widget()
{
delete ui;
}
void Widget::on_pushButton_clicked()
{
//获取输入框数据
QUrl url(ui->lineEdit->text());
//构造一个Http请求
QNetworkRequest request(url);
//发送请求
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释放
response->deleteLater();
});
}
实现效果
这里选用Plain Text Edit作为显示控件,是因为它是一个纯文本显示,不会对获取的html格式内容进行渲染,在输入框中输入要请求地址,点击按钮,则可以获取到响应信息
标签:Widget,Qt,网络,socket,ui,QString,服务器,客户端 From: https://blog.csdn.net/Tianzhenchuan/article/details/137268139