Qt - 实现HTTP服务器和HTTP客户端

news/2024/12/28 13:02:46/文章来源:https://www.cnblogs.com/zhuchunlin/p/18637403

1. WebSocket服务器和HTTP服务器的区别

WebSocket服务器和HTTP服务器是两种不同的服务器类型,它们在协议、连接方式和通信模式等方面有所区别。

  • 协议:HTTP服务器使用HTTP协议进行通信,而WebSocket服务器使用WebSocket协议。HTTP协议是无状态的,客户端发起请求,服务器响应请求后立即关闭连接。WebSocket协议允许在客户端和服务器之间建立持久连接,双向通信。
  • 连接方式:HTTP服务器采用"请求-响应"模式,即客户端向服务器发送请求,服务器响应后断开连接。每个请求都需要重新建立连接。WebSocket服务器在初始握手后,建立一个持久连接,允许双向通信,客户端和服务器可以随时发送消息。
  • 通信模式:HTTP服务器基于请求-响应模式,客户端发起请求,服务器做出响应。每个请求和响应都是独立的,没有持久性。WebSocket服务器支持双向通信,客户端和服务器可以通过发送消息进行实时交互,服务器可以主动推送消息给客户端。

总体而言,HTTP服务器适用于传统的客户端-服务器通信,每次请求都需要重新建立连接,适合请求响应式的场景。WebSocket服务器适用于需要实时双向通信的场景,适合聊天应用、实时数据更新等。

需要注意的是,WebSocket协议在建立连接时会使用HTTP协议进行初始握手,因此可以在HTTP服务器上实现WebSocket服务器。但是,WebSocket服务器提供更多的功能和优化,以支持实时通信需求。

 

2. 实现简单的HTTP服务器

具体代码:

httpserver.h

 
#ifndef HTTPSERVER_H
#define HTTPSERVER_H#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>class HttpServer : public QObject
{Q_OBJECT
public:explicit HttpServer(QObject *parent = nullptr);~HttpServer();QTcpSocket *socket;public slots:void onReadyRead();void connection();private:qint64 bytesAvailable() const;QTcpServer *server;signals:public slots:
};#endif // HTTPSERVER_H

httpserver.cpp

 
#include "httpserver.h"
#include <QDebug>
#include <QFile>HttpServer::HttpServer(QObject *parent) : QObject(parent)
{server = new QTcpServer(this);socket = new QTcpSocket(this);if(!server->listen(QHostAddress::Any, 8080)){qDebug() << "Web服务未启动";}else{qDebug() << "Web服务在端口8080等待客户端连接";}//有客户端连接时触发newConnection信号connect(server, &QTcpServer::newConnection, this, &HttpServer::connection);}void HttpServer::connection()
{//取出建立好连接的套接字socket = server->nextPendingConnection();//获取对方的IP和端口QString ip = socket->peerAddress().toString();qint16 port = socket->peerPort();QString temp = QString("[%1 : %2]: 成功连接").arg(ip).arg(port);qDebug() << temp;connect(socket,&QTcpSocket::readyRead,this,&HttpServer::onReadyRead);
}void HttpServer::onReadyRead()
{//QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());if(socket){//从通信套接字中取出内容QByteArray array = socket->readAll();QString request = QString::fromUtf8(array);qDebug() << "正在从浏览器读取数据= " << request;//QString::startsWith()函数判断一个字符串是否以某个字符串开头if(request.startsWith("GET"))//如果是GET请求{QFile file("/Users/Administrator/Documents/http_demo/index.txt");if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() << "文件打开失败";return;}QString tempStr = "";//临时字符串while (!file.atEnd())//判断是否读到文件末尾,如果已经达到末尾,返回 true,否则返回 false。{//tempStr = file.readLine();  //读取文件中一行tempStr = file.readAll();   //读取文件中所有内容//qDebug() <<"tempStr = "<<tempStr;}char *ch = tempStr.toLatin1().data();socket->write("HTTP/1.1 200 OK\r\n");socket->write("Content-Type: text/html\r\n");socket->write("\r\n");socket->write(ch);socket->flush();}}
}HttpServer::~HttpServer()
{socket->close();
}

main.cpp

 
#include <QApplication>
#include "httpserver.h"int main(int argc, char *argv[])
{QApplication a(argc, argv);HttpServer server;return a.exec();
}

index.txt

 
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>简易的在线计算器</title>
</head>
<body><form action="/test_cgi" method="get" align="center">操作数1:<br><input type="text" name="x"><br>操作数2:<br><input type="text" name="y"><br><br><input type="submit" value="计算"></form>
</body>
</html>

 

运行结果:

注意:

如果访问服务器时没有指定要访问的资源路径,那么浏览器会自动帮我们添加/,但此时仍然没有指明要访问web根目录下的哪一个资源文件,这时默认访问的是目标服务的首页。
大部分URL中的端口号都是省略的,因为常见协议对应的端口号都是固定的,比如HTTP、HTTPS和SSH对应的端口号分别是80、443和22,在使用这些常见协议时不必指明协议对应的端口号,浏览器会自动帮我们进行填充。

 

优化版:

注:此版本可以多个客户端与服务器通信。

httpserver.h

 
#ifndef HTTPSERVER_H
#define HTTPSERVER_H#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>class HttpServer : public QObject
{Q_OBJECT
public:explicit HttpServer(QObject *parent = nullptr);~HttpServer();public slots:void onReadyRead();void connection();void onDisconnected();private:qint64 bytesAvailable() const;QTcpServer *server;QList<QTcpSocket*> tcpSktList;//用来存储所有客户端socket的链表signals:public slots:
};#endif // HTTPSERVER_H

httpserver.cpp

 
#include "httpserver.h"
#include <QDebug>
#include <QFile>
#include <QHostAddress>HttpServer::HttpServer(QObject *parent) : QObject(parent)
{server = new QTcpServer(this);if(!server->listen(QHostAddress::Any, 8080)){qDebug() << "Web服务未启动";}else{qDebug() << "Web服务在端口8080等待客户端连接";}//有客户端连接时触发newConnection信号connect(server, &QTcpServer::newConnection, this, &HttpServer::connection);}void HttpServer::connection()
{//取出建立好连接的套接字QTcpSocket *socket = server->nextPendingConnection();//获取对方的IP和端口QHostAddress clientIp = socket->peerAddress();//客户端的IPqint16 port = socket->peerPort();//客户端的端口if(tcpSktList.contains(socket)){qDebug()<<QString("%1:%2的连接早已建立过").arg(clientIp.toString()).arg(port);}else{qDebug()<<QString("新的连接已建立 %1:%2").arg(clientIp.toString()).arg(port);tcpSktList.append(socket);//记录下客户端发起的连接connect(socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()));//客户端掉线处理connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));//客户端发来的数据处理}
}void HttpServer::onReadyRead()
{QTcpSocket* socket = static_cast<QTcpSocket*>(sender());if(socket){//从通信套接字中取出内容QByteArray array = socket->readAll();QString request = QString::fromUtf8(array);qDebug() << "正在从浏览器读取数据= " << request;//打印收到的来自客户端的消息if(request.startsWith("GET"))//如果是GET请求{QFile file("/Users/Administrator/Documents/http_demo/index.txt");if (!file.open(QIODevice::ReadOnly | QIODevice::Text)){qDebug() << "文件打开失败";return;}QString tempStr = "";//临时字符串while (!file.atEnd())//判断是否读到文件末尾,如果已经达到末尾,返回 true,否则返回 false。{//tempStr = file.readLine();  //读取文件中一行tempStr = file.readAll();   //读取文件中所有内容//qDebug() <<"tempStr = "<<tempStr;}char *ch = tempStr.toLatin1().data();socket->write("HTTP/1.1 200 OK\r\n");socket->write("Content-Type: text/html\r\n");socket->write("\r\n");socket->write(ch);socket->flush();}}
}void HttpServer::onDisconnected()
{QTcpSocket *socket = static_cast<QTcpSocket *>(sender());//获取对方的IP和端口QHostAddress clientIp = socket->peerAddress();//客户端的IPqint16 port = socket->peerPort();//客户端的端口qDebug()<<QString("客户端掉线 %1:%2").arg(clientIp.toString()).arg(port);tcpSktList.removeOne(socket);
}HttpServer::~HttpServer()
{//socket->close();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/860359.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

“代码之舟”——2024秋软工实践纪

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/SE2024这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/SE2024/homework/13315这个作业的目标 回顾这一学期所完成的软工任务,总结这一学期的收获学号 102202102 王子聪引言: 在上这门课之前还没有真正的体…

Python-DdddOcr的简单使用

前言:我们在做WEB端UI自动化时,会遇到图片验证码校验的登录方式。我在之前的文章也做过介绍:https://www.cnblogs.com/TSmagic/p/16082799.html (Pillow + pytesseract + tesseract-ocr 破解简单的图形验证码)https://www.cnblogs.com/TSmagic/p/16117861.html(Python + 超…

Omnissa ThinApp 2412 - 应用虚拟化软件

Omnissa ThinApp 2412 - 应用虚拟化软件Omnissa ThinApp 2412 - 应用虚拟化软件 Omnissa ThinApp, formerly VMware ThinApp 请访问原文链接:https://sysin.org/blog/omnissa-thinapp/ 查看最新版。原创作品,转载请保留出处。 作者主页:sysin.orgOmnissa ThinApp 通过将应用…

Omnissa App Volumes 4, version 2412 - 实时应用程序交付系统

Omnissa App Volumes 4, version 2412 - 实时应用程序交付系统Omnissa App Volumes 4, version 2412 - 实时应用程序交付系统 Omnissa App Volumes, formerly VMware App Volumes 请访问原文链接:https://sysin.org/blog/omnissa-app-volumes/ 查看最新版。原创作品,转载请保…

CSP-J2/S2 2024 游记

前情提要:CSP-J/S 2023 写这篇文章的时候,心情比较复杂。 哎,结局还算圆满。初赛 之前那个写的不好再写一遍() 两个都在 WFLS,也就是本校考 qaq。 J 在大礼堂考,没啥好说的,太简单了(除了格雷码,好难没学过 /ll) 乐,考试结束前 3min 还在改卷子() 省流:98。 S 在…

部署traefik 1.7服务

部署traefik服务主要是三个yaml文件:traefik-deployment.yaml,traefik-rbac.yaml,ui.yaml也可以使用traefik-ds.yaml,这个方式体现。 [root@k8smaster traefiks]# ll总用量 12-rw-r--r--. 1 root root 1114 12月 26 22:14 traefik-deployment.yaml-rw-r--r--. 1 root root …

2024.12.26 周四

2024.12.26 周四Q1. 1100 There is a ribbon divided into $n$ cells, numbered from $1$ to $n$ from left to right. Initially, an integer $0$ is written in each cell. Monocarp plays a game with a chip. The game consists of several turns. During the first turn, …

UML之集合类型

无论何时当我们要使用一个多值对象时,我们必须要清楚两个问题,一是这些值的顺序重要吗?二是允许重复值的存在吗?在编程语言中还会有其他的明确的信息,在UML中,只需明确这两个问题的答案即可确定对应的集合类型。 1.Set Set是一个不允许存在重复值且未排序的集合。 例如一…

《计算机基础与程序设计》第十四周学习总结

学期(2024-2025-1) 学号(20241412) 《计算机基础与程序设计》第十四周学习总结 作业信息这个作业属于哪个课程 <班级的链接> 2024-2025-1-计算机基础与程序设计这个作业要求在哪里 <作业要求的链接> 2024-2025-1计算机基础与程序设计第十四周作业)教材学习内容…

2024-2025-1 20241417 《计算机基础与程序设计》第十四周学习总结

2024-2025-1 20241417 《计算机基础与程序设计》第十四周学习总结 作业信息这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>2024-2025-1计算机基础与程序设计第十四周作业这个作业的目标 <《C语言…

【Windows】 国内安装Scoop包管理器(镜像加速)

由于国内github访问不通畅,且多数开源软件托管在github,导致scoop体验极差,甚至安装Scoop这一步都无法进行。国内有位作者将scoop主程序托管在gitee,增加分流逻辑处理安装与更新所涉及的资源。 链接: https://gitee.com/scoop-installer/scoop 安装scoop主程序 1.1 初次安…

07 _ Load Average:加了CPU Cgroup限制,为什么我的容器还是很慢?

07 _ Load Average:加了CPU Cgroup限制,为什么我的容器还是很慢?你好,我是程远。今天我想聊一聊平均负载(Load Average)的话题。 在上一讲中,我们提到过CPU Cgroup可以限制进程的CPU资源使用,但是CPU Cgroup对容器的资源限制是存在盲点的。 什么盲点呢?就是无法通过CP…