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

news2024/12/22 10:18:59

上一节,我们介绍了基于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];

    // 创建socket
    sockfd = 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);

    // 关闭socket
    close(sockfd);
    return 0;
}

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

3 结果

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

4 总结

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Transformers实战01-开箱即用的 pipelines

文章目录 简介安装pipelines图片转文本文本生成情感分析零训练样本分类遮盖词填充命名实体识别自动问答自动摘要 pipeline 背后做了什么&#xff1f;使用分词器进行预处理将预处理好的输入送入模型对模型输出进行后处理 简介 Transformers 是由 Hugging Face 开发的一个 NLP 包…

群辉部署小雅alist实现视听盛会

最近群辉搭建起来了&#xff0c;开始整蛊影视库&#xff0c;之前搞过nastool。这次折腾下小雅alist。 1.下载并安装 直接在群辉的docker里面下载映像 主要映射下端口和文件夹 #token mytoken.txt 获取地址&#xff1a;https://alist.nn.ci/zh/guide/drivers/aliyundriv…

牛客网刷题 | BC84 牛牛学数列2

目前主要分为三个专栏&#xff0c;后续还会添加&#xff1a; 专栏如下&#xff1a; C语言刷题解析 C语言系列文章 我的成长经历 感谢阅读&#xff01; 初来乍到&#xff0c;如有错误请指出&#xff0c;感谢&#xff01; 描述 这次牛牛又换了个数…

《控制系统实验与综合设计》综合四至六(含程序和题目)

1.电机模型辨识实验 1.1 实验目的 &#xff08;1&#xff09;掌握一阶系统阶跃响应的特点&#xff0c;通过实验加深对直流电解模型的理解&#xff1b; &#xff08;2&#xff09;掌握系统建模过程中参数的整定&#xff0c;体会参数变化对系统的影响&#xff1b; &#xff0…

SpringBoot解决CORS跨域——WebMvcConfigurationSupport

前端请求后端报错了。 状态码&#xff1a;403 返回错误&#xff1a;Invalid coRs request 增加配置类WebMvcConfig Configuration public class WebMvcConfig extends WebMvcConfigurationSupport {Overridepublic void addCorsMappings(CorsRegistry registry) {// 允许跨域…

JavaScript异步编程——10-async异步函数【万字长文,感谢支持】

异步函数&#xff08;用 async 声明的函数&#xff09; 异步函数的定义 使用async关键字声明的函数&#xff0c;称之为异步函数。在普通函数前面加上 async 关键字&#xff0c;就成了异步函数。语法举例&#xff1a; // 写法1&#xff1a;函数声明的写法async function foo1(…

杨校老师项目之基于单片机STC89C52的智能环境监测系统【嵌入式】

获取全套资料&#xff1a; 有偿获取&#xff1a;mryang511688 技术&#xff1a;C语言、单片机等 摘要&#xff1a; 此设计可分为三个主要部分。此中的温度和湿度的检测功能&#xff0c;通过操纵单总线型温湿度传感器DHT11以数字形式显示&#xff0c;实现了切确测得温湿度的功能…

Python | Leetcode Python题解之第89题格雷编码

题目&#xff1a; 题解&#xff1a; class Solution:def grayCode(self, n: int) -> List[int]:ans [0] * (1 << n)for i in range(1 << n):ans[i] (i >> 1) ^ ireturn ans

uniapp 实现下拉刷新 下滑更新

效果图 在app或者小程序中向下滑动 会出现刷新数据 ,而上拉到底 需要更新数据 功能实现 主要俩种方式 依赖生命周期 在page.json中开启 page.json "style" : {"navigationBarTitleText" : "小小练习","backgroundTextStyle": &qu…

Linux环境部署与命令技巧

Linux环境部署与命令技巧 安装Java 首先确保已经安装了Java。通过运行以下命令检查Java是否已安装&#xff1a; java -version # 查看Java版本如果未安装Java&#xff0c;可以使用以下命令安装OpenJDK&#xff1a; sudo yum install java-11-openjdk # 安装OpenJDK 11创建一个…

用Swagger(工具Knife4j )代替postman来进行构建、测试和调试 API

什么是Swagger&#xff1f; Swagger 是一个用于设计、构建和文档化 RESTful Web 服务的开源框架。它允许开发者设计 API&#xff0c;然后生成对应的 API 文档&#xff0c;提供给团队成员或者第三方开发者查阅。Swagger 的核心是 OpenAPI 规范&#xff08;之前称为 Swagger 规范…

来学习线程啦

线程的相关概念 程序 简单点说&#xff1a;程序就是我们写的代码&#xff1b;也可以理解为&#xff1a;为完成特定任务&#xff0c;用某种语言编写的一组指令的集合 进程 进程是指运行中的程序。 比如&#xff1a;我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系…

Centos 6.10 安装oracle10.2.0.1

由于阿里云机房要下架旧服务器&#xff0c;单位未购买整机迁移服务&#xff0c;且业务较老不兼容Oracle11g&#xff0c;所以新购买一台新服务器进行安装Oracle10.2.0.1 &#xff0c;后续再将数据迁移到新服务器上。 对外ip 内部ip 数据库版本 操作系统版本 实例名 源库 1…

【MATLAB】Enigma机加密原理与自实现

文章目录 什么是EnigmaEnigma机加密通信流程Enigma的物理构造Enigma的加密设置Enigma加密通信密码重新设置Enigma加密消息拼接注意 Enigma的解密分解设置Enigma解密通信密码重新设置Enigma解密消息 Enigma的弱点MATLAB自实现Enigma加密与解密Enigma_functionRotate_functiontes…

排序(一)----冒泡排序,插入排序

前言 今天讲一些简单的排序,冒泡排序和插入排序,但是这两个排序时间复杂度较大,只是起到一定的学习作用,只需要了解并会使用就行,本文章是以升序为例子来介绍的 一冒泡排序 思路 冒泡排序是一种简单的排序算法&#xff0c;它重复地遍历要排序的序列&#xff0c;每次比较相邻…

K8S内容

K8S介绍 1、故障迁移:当某一个node节点关机或挂掉后&#xff0c;node节点上的服务会自动转移到另一个node节点上&#xff0c;这个过程所有服务不中断。这是docker或普通云主机是不能做到的 2、资源调度:当node节点上的cpu、内存不够用的时候&#xff0c;可以扩充node节点&…

详细分清Session,Cookie和Token之间的区别,以及JWT是什么东西

Cookie Cookie是一种小型的文本文件&#xff0c;由网站在用户访问时存储在其计算机或移动设备上&#xff0c;Cookie主要用于跟踪、识别和存储有关用户的信息。 简单来说Cookie就是用来存储某些后端发送给前端的数据&#xff0c;例如我们登陆后&#xff0c;后端会返回一个登录…

求正方形阴影部分面积

正方形边长6&#xff0c;求阴影部分面积 xy6① vw6② 1/26v1/23x1/263③ 1/26v1/26y1/266④ ③是左下角三角形的面积&#xff0c;④是左上角三角形的面积。 求解方程组得到x2 阴影部分面积1/2*3x3.

海豚调度器如何看工作流是在哪个worker节点执行

用海豚调度器&#xff0c;执行一个工作流时&#xff0c;有时成功&#xff0c;有时失败&#xff0c;怀疑跟worker节点环境配置不一样有关。要怎样看是在哪个worker节点执行&#xff0c;在 海豚调度器 Web UI 中&#xff0c;您可以查看任务实例&#xff0c;里面有一列显示host&a…

网络安全快速入门(九)MySQL进阶操作

上一章我们了解了对表及库的基本增删查改操作&#xff0c;本章我们针对增删查改内容进行与一些拓展&#xff0c; 9.1字段修饰及数据类型 我们之前在创建表时用到的格式为&#xff1a; create table 表名 ( 字段名1 字段数据类型&#xff08;数据类型长度&#xff09;, 字段名2 …