基于HTTP GET方式获取网络时间的实现

上一节,我们介绍了基于NTP服务器获取网络时间的例子,但在有些情况下,比如我最近在使用RNDIS协议通过4G模块上网,这个协议不支持UDP协议,所以就用不了NTP服务器。或者有时候我们需要有更多的网络时间获取方式,以保证系统100%能获取到网络时间。本节就来介绍一下更通用的获取网络时间的方式:HTTP GET。

文章目录

  • 1 HTTP GET原理
    • 1.1 网络中的工作流程
    • 1.2 HTTP GET请求组成部分
    • 1.3 测试
  • 2 代码实现
    • 2.1 实现步骤
    • 2.2 完整代码
  • 3 结果
  • 4 总结

1 HTTP GET原理

本节的原理实际上就是类似浏览器访问网站一样获取网站的数据,只需要找到一个能显示时间的网站就行了。下面就来了解一下使用socket请求HTTP GET网络数据的原理。

1.1 网络中的工作流程

  1. 用户发起请求: 用户通过浏览器或应用向服务器发送一个HTTP GET请求。
  2. 服务器处理请求: 服务器接收到请求后,解析URL和头部信息,根据请求的资源进行处理。
  3. 发送响应: 服务器将请求的数据(如HTML页面、图片等)打包在HTTP响应中返回给客户端。
  4. 客户端处理响应: 客户端(通常是浏览器)接收响应并根据需要渲染或处理数据。

1.2 HTTP GET请求组成部分

  • 请求行: 包括方法(GET)、请求的URI和HTTP版本。
  • 请求头: 包含请求的元数据,如用户代理信息、接受的内容类型等。
  • 空行: 请求头后面跟一个空行,表示请求头的结束。
  • 请求体: GET请求通常没有请求体,因为请求的数据包含在URI中。

下面是一些常见的HTTP请求头字段,这些字段在HTTP GET请求中经常使用:

1. Host

  • 描述Host 请求头指定了被请求资源的互联网主机和端口号,它通常由URI提供。由于一个服务器可能寄存多个域名,Host 请求头用来指定请求的是哪个域名。
  • 示例:如果请求 http://www.example.com/index.html,那么 Host 请求头将是:
Host: www.example.com

2. User-Agent

  • 描述User-Agent 请求头包含了一个特征字符串,用于让服务器识别客户端使用的操作系统,浏览器和浏览器版本等信息。这可以帮助服务器提供与设备兼容的响应。
  • 示例:一个典型的 User-Agent 请求头可能看起来像这样:
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36

3. Accept

  • 描述Accept 请求头用于告诉服务器,客户端能够处理哪些媒体类型。服务器可以根据这个头部信息决定返回什么类型的内容。
  • 示例:表明客户端可以处理HTML和XML,以及它们的特定版本:
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8

4. Accept-Language

  • 描述Accept-Language 请求头用于告诉服务器,客户端希望优先接收哪种自然语言(如英语、中文等)。服务器可以据此返回相应语言的内容,实现本地化。
  • 示例
Accept-Language: en-US,en;q=0.5

5. Accept-Encoding

  • 描述Accept-Encoding 请求头用于告诉服务器,客户端支持哪些压缩格式。服务器可以选择一个适合的压缩方法,以减小响应数据的体积,提高传输效率。
  • 示例
Accept-Encoding: gzip, deflate, br

6. Connection

  • 描述Connection 请求头用于控制客户端和服务器之间的连接管理,常用的值有 keep-aliveclosekeep-alive 告诉服务器保持连接打开,以便未来的请求可以使用同一连接,close 则相反。
  • 示例
Connection: keep-alive

示例: 一个HTTP GET请求的结构

GET /example?page=1 HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Connection: keep-alive

当然,并非所有请求头都是必须的。某些头部信息如 User-Agent、Accept、Accept-Language 等是可选的,这些头部提供了关于客户端偏好和能力的信息,可以帮助服务器更优化地响应请求,但不包含这些头也不会阻止请求的基本功能。只有在特定场景下,例如多域托管、特定内容协商或需管理连接时,才需要特定的请求头。

1.3 测试

我们直接在电脑上用TCP客户端测试一下这样是否可行,首先我们获取服务器的IP:
在这里插入图片描述
然后我们连接这个IP,HTTP端口号一般为80,并发送请求报文:
在这里插入图片描述
可以看到,我们请求访问网页后,对方返回了HTTP头和网页内容,即我们成功获取了网页中的时间。

2 代码实现

这里在Linux环境下为例对HTTP网络时间进行获取,使用标准的POSIX/BSD套接字编程,这样如果想在单片机中LwIP实现的话,也可以直接使用。

2.1 实现步骤

1、HTTP时间服务端地址
这里以苏宁的时间服务器为例:https://quan.suning.com/getSysTime.do在这里插入图片描述HTTP的端口一般都是80:

#define SERVER_PORT 80
#define SERVER_HOST "quan.suning.com"

2、创建套接字、解析域名
实际上HTTP也是基于TCP协议实现的,整个过程无非就是建立一个TCP连接,所以首先我们就是创建一个套接字。接着像苏宁这种大网站,一般会根据不同的地区分配不同的IP服务器以分担服务器负担,所以IP在不同地区解析出来都不一样,这里我们做一下域名DNS解析,用gethostbyname函数将域名解析为IP。

int sockfd;
struct hostent *server;// 创建socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
// 获取服务器的地址
server = gethostbyname(SERVER_HOST);

3、建立连接
填充一下服务端结构体,建立连接。

// 填充服务器地址结构体
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
memcpy(&serveraddr.sin_addr.s_addr, server->h_addr, server->h_length);
serveraddr.sin_port = htons(SERVER_PORT);
// 连接到服务器
connect(sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr));

4、请求网页数据并读取

#define REQUEST "GET /getSysTime.do HTTP/1.1\r\nHost: quan.suning.com\r\n"   \"Connection: close\r\n\r\n"
char response[4096];
// 发送GET请求
write(sockfd, REQUEST, strlen(REQUEST);
read(sockfd, response, sizeof(response) - 1) ;

简单分析一下这个请求头

  • Host: quan.suning.com
    • 这个头是必需的,它指定了请求发送到的服务器的域名。在HTTP/1.1版本中,每个请求都必须包含Host头,因为一个服务器上可能托管多个域,服务器通过这个头部信息来确定要访问的具体域。
  • Connection: close
    • 这个头部控制着连接的管理,close 的值意味着一旦请求完成后,客户端和服务器之间的连接将关闭,不会用于后续的请求。

2.2 完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>#define SERVER_PORT 80
#define SERVER_HOST "quan.suning.com"
#define REQUEST "GET /getSysTime.do HTTP/1.1\r\nHost: quan.suning.com\r\nConnection: close\r\n\r\n"int main() {int sockfd;struct sockaddr_in serveraddr;struct hostent *server;char response[4096];// 创建socketsockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) {perror("ERROR opening socket");exit(1);}// 获取服务器的地址server = gethostbyname(SERVER_HOST);if (server == NULL) {fprintf(stderr, "ERROR, no such host\n");exit(0);}// 填充服务器地址结构体memset(&serveraddr, 0, sizeof(serveraddr));serveraddr.sin_family = AF_INET;memcpy(&serveraddr.sin_addr.s_addr, server->h_addr, server->h_length);serveraddr.sin_port = htons(SERVER_PORT);// 连接到服务器if (connect(sockfd, (struct sockaddr *) &serveraddr, sizeof(serveraddr)) < 0) {perror("ERROR connecting");exit(1);}// 发送GET请求if (write(sockfd, REQUEST, strlen(REQUEST)) < 0) {perror("ERROR writing to socket");exit(1);}// 读取响应memset(response, 0, sizeof(response));if (read(sockfd, response, sizeof(response) - 1) < 0) {perror("ERROR reading from socket");exit(1);}// 打印响应printf("%s\n", response);// 关闭socketclose(sockfd);return 0;
}

注意,苏宁的网站有流量控制,有时候访问会出现系统忙,一般再请求一次即可,这个自己在代码中判断。

3 结果

编译后运行:
在这里插入图片描述
可以看到,结果和用TCP客户端上位机获取的一样,我们只需要做一些文本的操作就能获取到当前的时间了。

4 总结

本篇博客介绍了如何在Linux下使用C语言和Socket API发起HTTP GET请求。这个示例程序可以扩展到其他类型的HTTP请求和不同的API服务。如果不想用苏宁的服务器,可以随便请求一个网站和不存在的网页,如果网站用的是nginx的话,访问不存在的网页也会返回一个nginx时间。

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

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

相关文章

Dart 3.4 发布:Wasm Native Macros(宏)

Google I/O 的结束&#xff0c;除了 Flutter 3.22 的发布 &#xff0c;Dart 3.4 也迎来了它是「史诗级」的更新&#xff0c;之所以这么说&#xff0c;就是因为 Wasm Native 的落地和 Macros 的实验性展示。 在此之前&#xff0c;其实我也提前整理过一些对应的内容&#xff0c;…

平安养老险深圳分公司携手福海街道开展5.12防灾减灾活动

在构建和谐社会、倡导人文关怀的当下&#xff0c;平安养老险深圳分公司以高度的社会责任感和深厚的人文情怀&#xff0c;持续关注老年人的健康与安全。在今年“5.12防灾减灾日”来临之际&#xff0c;公司积极响应倡议&#xff0c;于5月10日携手福海街道举办了一场别开生面的消防…

校园电话机对于校园信息化管理非常重要

任何一部校园电话机都有信息办理渠道&#xff0c;并且发挥着重要的效果&#xff0c;能够满意整个机器的更快速运作。然后使学生能够取得一个更好的运用条件&#xff0c;学生在运用产品的过程中&#xff0c;要经过正确的操作环节才能够发挥产品的优胜功能&#xff0c;然后到达一…

[Algorithm][回溯][组合][目标和][组合总和]详细讲解

目录 1.组合1.题目链接2.算法原理详解3.代码实现 2.目标和1.题目链接2.算法原理详解3.代码实现 3.组合总和1.题目链接2.算法原理详解3.代码实现 1.组合 1.题目链接 组合 2.算法原理详解 思路&#xff1a;每次都只选一个数&#xff0c;此后只能选它后面的数函数设计&#xff…

金万维动态域名小助手怎么用?

金万维动态域名小助手是一个域名检测工具&#xff0c;使用此工具可以进行检测域名解析是否正确、清除DNS缓存、修改DNS服务器地址及寻找在线客服&#xff08;仅支持付费用户&#xff09;等操作。对不懂网络的用户是一个很好的检测域名的工具&#xff0c;下面我就讲解一下金万维…

【class8】人工智能初步(图像识别-----卷积神经网络)

上节回顾 上节课&#xff0c;我们简单了解了图像识别和深度学习的相关知识。 快速回顾一下吧&#xff5e; A图像识别是以图像的主要特征为基础的。B. 图像分辨率决定图像的质量。 C&#xff0e; 像素是图像中的最小单位D. 在图像识别的原理上&#xff0c;计算机和人类在本质…

VNA校准补充知识点

双端口校准中&#xff0c;SLOT已知直通校准&#xff1b;SLOR未知直通校准&#xff1b;后者精度更高 其余校准方式补充 1.增强型频响校准&#xff08;比SOLT简单&#xff09;&#xff0c;适用于器件的单向测量&#xff08;S11,S21&#xff09; 2.SOLR&#xff08;未知直通校准&…

Java聚合项目打包运行笔记

聚合项目创建 略 聚合项目打包配置 父工程 pom文件添加 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>…

一本书打通SLAM在智能汽车/自动驾驶领域应用

自动驾驶技术已成为当今数字化时代汽车行业的热点话题之一。随着技术的不断成熟&#xff0c;越来越多的车辆采用激光SLAM&#xff08;即时定位与地图构建&#xff09;和视觉SLAM技术&#xff0c;实现更高层次的智能网联汽车。SLAM技术在智能网联汽车中的应用是非常重要的&#…

深入解析Linux逻辑卷管理器(LVM)

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《Linux &#xff1a;从菜鸟到飞鸟的逆袭》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、前言 1、Linux的起源与发展 2、什么是逻辑卷管理器&…

Kubernetes学习-深入Pod篇(二) 探针技术详解与应用

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Kubernetes渐进式学习-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 1. 前言 2. 探针是什么 3. 探针的分类 3.1. StartupProbe(启动…

Spring WebFlux 初探-响应式编程-021

&#x1f917; ApiHug {Postman|Swagger|Api...} 快↑ 准√ 省↓ GitHub - apihug/apihug.com: All abou the Apihug apihug.com: 有爱&#xff0c;有温度&#xff0c;有质量&#xff0c;有信任ApiHug - API design Copilot - IntelliJ IDEs Plugin | Marketplace The Nex…