[Qt][Qt 网络][下]详细讲解


1.TCP Socket

1.核心API概览

  • 核⼼类是两个:QTcpServerQTcpSocket
  • QTcpServer用于监听端口,和获取客户端连接
    • listen(const QHostAddress&, quint16 port):绑定指定的地址和端⼝号,并开始监听
      • 成员方法
      • 对标原⽣API:bind() 和listen()
    • nextPendingConnection():从系统中获取到⼀个已经建⽴好的tcp连接
      • 返回⼀个QTcpSocket,表⽰这个客⼾端的连接
        • 通过这个socket对象完成和客⼾端之间的通信
      • 成员方法
      • 对标原⽣API:accept()
    • newConnection():有新的客⼾端建⽴连接好之后触发
      • 信号
      • 类似于IO多路复用的通知机制
  • QTcpSocket⽤于客⼾端和服务器之间的数据交互
    • readAll():读取当前接收缓冲区中的所有数据,返回QByteArray对象
      • 成员方法
      • 对标原生API:read()
    • write(const QByteArray &):把数据写⼊socket中
      • 成员方法
      • 对标原生API:write()
    • deleteLater():暂时把socket对象标记为⽆效,Qt会在下个事件循环中析构释放该对象
      • 成员方法
      • 类似于"半⾃动化的垃圾回收"
    • readyRead():有数据到达并准备就绪时触发
      • 信号
      • 类似于IO多路复⽤中的通知机制
    • disconnected():连接断开时触发
      • 信号
      • 类似于IO多路复⽤中的通知机制

2.回显服务器

// 构造函数中
{
	server = new QTcpServer(this);

	// 通过信号槽, 指定如何处理连接.
	connect(server, &QTcpServer::newConnection, 
			this, &Widget::ProcessConnection);
	
	// 绑定并监听端口号
	if (!ret = server->listen(QHostAddress::Any, 2333)) 
	{
	    QMessageBox::critical(this, "服务器启动失败!", server->errorString());
	    exit(1);
	}
}

void Widget::ProcessConnection()
{
    // 通过 server 拿到一个 socket 对象, 通过这个对象来和客户端进行通信
    QTcpSocket* clientSocket = tcpServer->nextPendingConnection();
    
    QString log = "[" + clientSocket->peerAddress().toString() + ":" + 
        			QString::number(clientSocket->peerPort()) + "] 客户端上线!";
    ui->listWidget->addItem(log);

    // 通过信号槽, 来处理客户端发来请求的情况
    connect(clientSocket, &QTcpSocket::readyRead, this, [=]() {
        // a) 读取出请求数据,此处 readAll 返回的是 QByteArray, 通过赋值转成 QString
        QString request = clientSocket->readAll();
        
        // b) 根据请求处理响应
        const QString& response = Process(request);
        
        // c) 把响应写回到客户端
        clientSocket->write(response.toUtf8());
        
        // d) 把上述信息记录到日志中.
        QString log = "[" + clientSocket->peerAddress().toString() + ":" + 
            			QString::number(clientSocket->peerPort()) + "] "
                		+ " req: " + request + ", resp: " + response;
        ui->listWidget->addItem(log);
    });

    // 通过信号槽, 来处理客户端断开连接的情况.
    connect(clientSocket, &QTcpSocket::disconnected, this, [=]() {
        // a) 把断开连接的信息通过日志显示出来.
        QString log = "[" + clientSocket->peerAddress().toString() + ":" + 
            		QString::number(clientSocket->peerPort()) + "] 客户端下线!";
        ui->listWidget->addItem(log);
        
        // b) 手动释放 clientSocket. 直接使用 delete 是下策, 使用 deleteLater 更加合适
        clientSocket->deleteLater();
    });
}

QString Widget::Process(const QString request)
{
    return request;
}

3.回显客户端

// 构造函数中
{
	socket = new QTcpSocket(this);
	
	// 服务器建立连接,此处是非阻塞的IO通信
	socket->connectToHost("127.0.0.1", 2333);
	
	// 连接信号槽, 处理响应
	connect(socket, &QTcpSocket::readyRead, this, [=]() {
	    // a) 读取出响应内容
	    QString response = socket->readAll();
	    
	    // b) 把响应内容显示到界面上.
	    ui->listWidget->addItem("服务器说: " + response);
	});
	
	// 等待连接建立的结果. 确认是否连接成功.
	if (!socket->waitForConnected()) 
	{
	    QMessageBox::critical(this, "连接服务器出错", socket->errorString());
	    exit(1);
	}
}

void Widget::on_pushButton_clicked()
{
    const QString& text = ui->lineEdit->text();
    
    socket->write(text.toUtf8());
    
    ui->listWidget->addItem("客户端说: " + text);
    ui->lineEdit->setText("");
}

2.HTTP Client

  • Qt只提供了Http客户端,并没有提供Http服务端的库
  • 关键类主要是三个:QNetworkAccessManager , QNetworkRequest , QNetworkReply
  • QNetworkAccessManager提供了HTTP的核⼼操作
    • get(const QNetworkRequest&):发起⼀个HTTP GET请求,返回QNetworkReply对象
      • 本身不是阻塞函数,只负责发出去请求,不负责等请求回来
      • 收是QNetworkReply负责的,会收到finished信号
    • post(const QNetworkRequest&, const QByteArray&):发起⼀个HTTP POST请求,返回QNetworkReply对象
  • QNetworkRequest表⽰⼀个HTTP请求(不含body),如果需要发送⼀个带有body的请求(⽐如post),会在QNetworkAccessManagerpost()中通过单独的参数来传⼊body
    • QNetworkRequest(const QUrl&):通过URL构造⼀个HTTP请求
    • setHeader(QNetworkRequest::KnownHeaders header, const QVariant& value):设置请求头
      • QNetworkRequest::KnownHeaders是⼀个枚举类型,常⽤取值
        • ContentTypeHeader:描述body的类型
        • ContentLengthHeader:描述body的⻓度
        • LocationHeader:⽤于重定向报⽂中指定重定向地址
        • CookieHeader:设置cookie
        • UserAgentHeader:设置User-Agent
  • QNetworkReply表⽰⼀个HTTP响应,这个类同时也是QIODevice的⼦类
    • error():获取出错状态
    • errorString():获取出错原因的⽂本
    • readAll():读取响应body
    • header(QNetworkRequest::KnownHeaders header):读取响应指定header的值
    • finished():为一个信号,在客⼾端收到完整的响应数据之后触发
  • 示例
    // 构造函数中
    {
        manager = new QNetworkAccessManager(this);
    }
    
    void Widget::on_pushButton_clicked()
    {
        // 1. 获取到输入框中的 url
        QUrl url(ui->lineEdit->text());
        
        // 2. 构造一个 HTTP 请求对象
        QNetworkRequest request(url);
        
        // 3. 发送请求
        QNetworkReply* response = manager->get(request);
        
        // 4. 通过信号槽, 来处理响应
        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();
        });
    }
    

3.其他模块

  • Qt中还提供了FTP,DNS,SSL等⽹络相关的组件⼯具,有需要可以具体学习,查阅官方文档
  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DieSnowK

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值