c语言 json 请求_用C语言实现简单的HTTP数据请求

2023-05-16

转载或者引用本文内容请注明来源及原作者!

前言

之前在做嵌入式开发时遇到一个项目,需要用http与服务器通信,移植了一个http库,编译后发现固体太大,flash都差点不够放了,要实现的功能也就简单的信息获取和上报而已。于是我决定用socket简单的实现这些功能。

什么是http?超文本传输协议(HyperTextTransferProtocol,缩写:HTTP)是一种用于分布式、协作式和超媒体信息系统的应用层协议。基于TCP/IP通信协议来传递数据。

浏览器是如何访问地址的?

我们平常在浏览器地址栏输入http网址后,浏览器会做以下动作:从网址(url)中取出域名,然后通过DNS服务器获取到对应的IP地址。

通过IP地址连接到服务器(默认端口为80)。

浏览器合以HTTP协议合成请求报文,并发送给服务器。

服务器返回响应报文。

服务器断开TCP。

浏览器以HTTP协议解析响应报文,得到内容并做出相应的处理(一般会得到html文本,浏览器通过html生成页面并显示出来)。

HTTP请求报文格式

例如, 下面的网址:

http://www.zhihu.com/people/cheng-tian-zhe

合成请求报文应该是:

GET /people/cheng-tian-zhe HTTP/1.1

Host: www.zhihu.com

HTTP响应报文格式

在这里,我们只关注状态码、Content-Length字段、主体:状态码200表示成功。

Content-Length可以获取主体的大小,以便申请内存接收主体内容。(不一定有)

主体就是我们要得到的数据。

代码

下面是一个获取服务器时间的例子,esp8266通过http请求服务器时间。

请求报文:

GET /bbt/nowtime HTTP/1.1

Host: xxx.xxx.com:80

//这里需要有个"\r\n"

响应报文:

Content-Type:application/json;charset=UTF-8

Date:Tue, 17 Nov 2020 08:42:27 GMT

... //这里省略部分字段

Connection:close

{"datas":"2020-11-17 16:41:05","resp_code":0,"resp_msg":"SUCCESS","successed":true}

1、通过域名获取ip

int bbtGetIpByHostname(char *host_name, char *first_ip)

{

char **pptr;

const char *first;

struct hostent *hptr;

char str[32] = {'\0'};

/* 调用gethostbyname()。结果存在hptr结构中 */

if((hptr = gethostbyname(host_name)) == NULL)

{

ESP_LOGE(TAG, " gethostbyname error for host:%s", host_name);

return -1;

}

/* 根据地址类型,将地址打出来 */

switch(hptr->h_addrtype)

{

case AF_INET:

case AF_INET6:

pptr=hptr->h_addr_list;

/* 将刚才得到的所有地址都打出来。其中调用了inet_ntop()函数 */

for(; *pptr!=NULL; pptr++)

ESP_LOGI(TAG, " address:%s", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str)));

first = inet_ntop(hptr->h_addrtype, hptr->h_addr, str, sizeof(str));

// ESP_LOGI(TAG, first address: %s\n", first); if(first)

memcpy(first_ip, str, 32);

break;

default:

ESP_LOGI(TAG, "unknown address type");

break;

}

return 0;

}

2、创建socket并连接服务器

int socket_open_http(char *host_name, char *ip_out)

{

int socketId;

struct sockaddr_in serv_addr;

int status;

if (bbtGetIpByHostname(host_name, ip_out))

return -1;

socketId = socket(AF_INET, SOCK_STREAM, 0);

if((int)socketId < 0)

{

ESP_LOGE(TAG, "Create a socket failed!");

return -1;

}

memset(&serv_addr, 0, sizeof(serv_addr));

unsigned long net_ip = inet_addr(ip_out);

if(net_ip == INADDR_NONE) {

ESP_LOGE(TAG, "net_ip failed!");

return -1;

}

serv_addr.sin_addr.s_addr = net_ip;

serv_addr.sin_port = htons(80); // 端口默认80 serv_addr.sin_family = AF_INET;

status = connect(socketId, (struct sockaddr*)&serv_addr, sizeof(serv_addr));

if(status!=0) {

ESP_LOGE(TAG, "Connecting failed!");

close(socketId);

return -1;

}

ESP_LOGI(TAG, "connect sucess");

return socketId;

}

3、合成并发送请求报文,接收响应

#define BBT_HTTP_HOST_NAME"xxx.xxx.com"//域名#define BBT_HTTP_TIME_PATH"/bbt/nowtime"//路径

#defineBBT_HTTP_TIMEOUT_S2//超时时间#define TCP_BUFFSIZE 1460

int bbtGetServerTime(void)

{

char http_ip[32] = {0};

int http_skt = socket_open_http(BBT_HTTP_HOST_NAME, http_ip);

if (http_skt <= 0)

return -1;

//这里控制模块的请求时间,设置tcp收发超时,如果没有要求可以不设置 struct timeval timeout = {BBT_HTTP_TIMEOUT_S, 0};

//设置发送超时 setsockopt(http_skt, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(struct timeval));

//设置接收超时 setsockopt(http_skt, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(struct timeval));

char *http_request;

const char *GET_TIME =

"GET %s HTTP/1.1\r\n"

"Host: %s:%d\r\n"

"\r\n";

// 合成请求报文 int get_len = asprintf(&http_request, GET_TIME, BBT_HTTP_TIME_PATH, http_ip, 80);

if (get_len < 0) {

ESP_LOGE(TAG, "GET request buffer error");

goto GET_TIME_ERR;

}

// 发送报文 int send_len = send(http_skt, http_request, get_len, 0);

free(http_request);

if (send_len < 0)

goto GET_TIME_ERR;

// 接收响应(这里假设一包能收完) char tcp_buf[TCP_BUFFSIZE] = {0};

memset(tcp_buf, 0x00, TCP_BUFFSIZE);

int buff_len = recv(http_skt, tcp_buf, TCP_BUFFSIZE, 0);

if (buff_len < 0) {

ESP_LOGE(TAG, "receive data error!");

goto GET_TIME_ERR;

}

// 释放socket close(http_skt);

printf("tcp_buf =\n%s\n", tcp_buf);

/* 处理tcp_buf中的响应报文 */

/* 可以以"\n"取行,一直取到一个只有2个字节的即"\r\n" ,下一行就是主体*/

return 0;

GET_TIME_ERR:

close(http_skt);

return -1;

}

最后说下GET和POST的区别

GET和POST都是HTTP协议中的常用请求的方法,那么它们究竟有什么不同?

事实上,对于简单的http数据请求来说,两者之间并没有多大的区别。但当时项目负责服务器的同学提供的接口一般都用POST,而不用GET,这是为什么呢?

具体原因有很多,他跟我说了主要的几点:GET请求的参数是有长度限制的,而POST没有。

GET请求的参数只能是ASCII字符,而POST没有限制。

GET请求的参数是直接显示在URL上,相比之下POST更安全。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c语言 json 请求_用C语言实现简单的HTTP数据请求 的相关文章

  • Mongoose查询结果是只读的吗?

    如何修改 Mongoose 查询返回的对象 假设我们有以下模式 var S new mongoose Schema name String field String 我对结果进行了以下查询和修改 var retrieve function
  • 使用 JSONKit 解析 JSON 文件

    我正在构建一个音叉应用程序 货叉应允许最多 12 个预设节距 此外 我希望允许用户选择一个主题 每个主题都会加载一组预设 不必使用所有预设 我的配置文件看起来像这样 theme A3 comment An octave below conc
  • Javascript 将对象推送为克隆

    我将 d3 用于交互式网络应用程序 我需要绑定的数据在交互过程中发生变化 并且由 JSON 变量中的一些选定对象组成 为此 我在 JSON 变量上使用了映射 并进行了一些查询来选择适当的对象 对象被推送到列表中 并且该列表被绑定为新数据 我
  • Java Junit 测试 HTTP POST 请求

    我需要测试以下方法而不改变方法本身 该方法向服务器发出 POST 方法 但我需要制作一个独立于服务器的测试用例 在将其重定向到本地文件之前 我测试了类似的方法 但为此我将协议指定为文件 主机名指定为 localhost 端口指定为 1 我的
  • 通过 JSONP 通过 CDN 传输静态 JSON 文件

    我有大量 JSON 格式的静态 很少变化的数据 为了提高我的 ASP NET MVC 应用程序性能 我想将它们移动到 CDN Amazon Cloud Front 然而 当我这样做时 跨域策略启动 jQuery 进行 HTTP OPTION
  • 在Python中,如何通过去掉括号和大括号来打印Json

    我想以一种很好的方式打印 Json 我想去掉方括号 引号和大括号 只使用缩进和行尾来显示 json 的结构 例如 如果我有一个像这样的 Json A A1 1 A2 2 B B1 B11 B111 1 B112 2 B12 B121 1
  • PySpark - RDD 到 JSON

    我有一个 Hive 查询返回以下格式的数据 ip category score 1 2 3 4 X 5 10 10 10 10 A 2 1 2 3 4 Y 2 12 12 12 12 G 10 1 2 3 4 Z 9 10 10 10 10
  • 用于一个自定义字段的 Jackson 反序列化器?

    我相信我们需要一个自定义反序列化器来对我们类中的一个字段执行特定的操作 看来一旦我这样做了 我现在就负责反序列化所有其他字段 有没有办法让杰克逊反序列化所有字段except我在这里关心的那个人 public class ThingDeser
  • 下载前获取文件大小并计算已下载的文件大小 (http+ruby)

    谁能帮我 get the 之前的文件大小我开始下载 显示多少 已下载 require net http require uri url http www onalllevels com 2009 12 02TheYangShow Squid
  • 如何向 node-http-proxy 响应添加标头

    我需要在第三方服务上解决CORS 所以我想构建一个代理来添加标头 Access Control Allow Origin 为什么这段代码没有添加标题 httpProxy require http proxy var URL https th
  • 如何解析多态 JSON 数组?

    我有一个 JSON 格式的文件 其中包含个人用户的记录 一些用户的记录中间有一个评论字段 我只想解析顶级项目 全名 贡献者姓名 电子邮件 使用 Newtonsoft JSON 解析器 但我似乎无法让它识别单个对象 当我将整个字符串解析为一个
  • Java 中的下载管理器 [关闭]

    Closed 这个问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我需要通过 FTP HTTP 从 Java 获取几个大文件 几个演出 有现成的库 java 命令行工具
  • 将新属性动态添加到 Node 中现有的 JSON 数组中

    我需要添加当前 JSON 中不存在的属性 json 对象如下所示 var jsonObj result OK data 我想在 数据 中添加温度 我可以像下面那样做 jsonObj data push temperature 然后 我想在
  • 使用 HTTP-Basic 身份验证发出 HTTP GET 请求

    我需要为我正在开发的 Flash Player 项目构建一个代理 我只需要使用 HTTP Basic 身份验证向另一个 URL 发出 HTTP GET 请求 并提供来自 PHP 的响应 就好像 PHP 文件是原始源一样 我怎样才能做到这一点
  • Google 地图查询返回的 JSON 包含像 \x26 这样的编码字符(如何解码?)

    在 Java 应用程序中 我获取 JSON 来自 Google 地图 其中包含以下字符 x26我想将其转换为其原始字符 据我所知 这是一个 UTF 8 表示法 但我不完全确定 在源 JSON 中 可能会出现各种编码字符 例如 x3c div
  • 如何强制控制器/操作使用 JsonValueProvider

    再会 我正在使用 ASP NET MVC 3 其中JsonValueProvider http haacked com archive 2010 04 15 sending json to an asp net mvc action met
  • json、rails、javascript 中的解析错误

    我需要将 ruby 数组放入 javascript 数组中 但出现解析错误 var characters 这就是我将 ruby 嵌入到内联 javascript 中的方式 但它出现了解析错误 我应该如何将此 ruby 数组放入 javasc
  • 如何在 Android 上的 HttpPost 中发送 unicode 字符

    我试图在我的应用程序中允许多语言支持 这会发出 HTTP post 来上传新消息 我需要做什么才能支持日语和其他非拉丁语语言 我的代码目前看起来像这样 note the msg string is a JSON message by the
  • 如何将 yii2 Restful api 中两个表的关系数据显示为 json 格式

    我遇到了将两个表中的数据显示为 JSON 格式并在 yii2 Restful api 上工作的问题 这是我的结构数据库 TABLE volunteer volunteer id int 11 NOT NULL auto increment
  • 如何为 Jackson 编写一个包罗万象的(反)序列化器

    当您提前知道类型时 编写自定义序列化器非常容易 例如 MyType一个人可以写一个MyTypeSerializer extends StdSerializer

随机推荐