糖尿病康复,内容丰富有趣,生活中的好帮手!
糖尿病康复 > C语言实现http post请求和get请求 post请求可以上传图片和文件

C语言实现http post请求和get请求 post请求可以上传图片和文件

时间:2019-10-06 10:57:48

相关推荐

C语言实现http post请求和get请求 post请求可以上传图片和文件

文章目录

1.http协议简介2.http协议分析2.1 http请求2.1.1 请求行2.1.1.1 请求方法2.1.1.2 URL2.1.1.3 协议版本2.1.1.4 请求行总结 2.1.2 请求头部2.1.3 请求数据 2.2 http响应2.2.1 状态行2.2.2 消息报头2.2.3 响应正文 3. 代码分析(可在arm平台中直接使用,全c实现)3.1 tcp基于协议代码3.2 基于http协议代码和测试用例

1.http协议简介

http协议叫做超文本传输协议,HTTP是一个基于TCP/IP通信协议来传递数据,本章讲解http的请求和http的响应报文解析

2.http协议分析

本小节主要讲解http的请求报文和响应报文

2.1 http请求

http请求主要有请求行,请求头部,空行,和请求数据组成

2.1.1 请求行

请求行主要有请求方法,url和协议版本组装但是,有严格的格式要求,下面就来具体的解析

2.1.1.1 请求方法

请求方法主要有:GET方法, post方法,opions ,Put ,Head ,Delete ,Trace 但是这里我们主要讲解的是get方法,和post方法这两种常见的方法。

get方法:

get请求通常用于获取服务器资源,也可以提交数据,但是通过url的方式提交数据是极其不安全的,因为数据会直接让人可以看到。例如:Http://127.0.0.1/login.jsp?Name=zhangshi&Age=30, 而且传输的的数据大小会受到限制,因此进行数据提交或者上传文件时,建议用post的请求

post方法:

post方法是GET方法的一个替代方法,它主要是向Web服务器提交表单数据,尤其是大批量的数据。post方法克服了GET方法的一些缺点。通过POST方法提交表单数据时,数据不是作为URL请求的一部分而是作为标准数据传送给Web服务器,这就克服了GET方法中的信息无法保密和数据量太小的缺点。因此,出于安全的考虑以及对用户隐私的尊重,通常表单提交时采用POST方法

2.1.1.2 URL

URL就是统一资源定位器(UniformResourceLocator:URL)。通俗地说,它是用来指出某一项信息的所在位置及存取方式;更严格一点来说,URL就是在WWW上指明通讯协议以及定位来享用网络上各式各样的服务功能。也就是告诉服务器,我要从哪个位置获取你资源

2.1.1.3 协议版本

http协议有以下版本:

HTTP/0.9HTTP/1.0HTTP 1.1HTTP/2.0

具体各个版本有什么更新就不具体介绍了,此字段主要是想做版本的兼容

2.1.1.4 请求行总结

http的样例如下:

请求方法 url 协议版本GET /test HTTP/2.0

2.1.2 请求头部

请求头部由关键字/值对组成,每行一对,关键字和值用英文冒号“:”分隔。请求头部通知服务器有关于客户端请求的信息,常见的有如下

实例:

User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3Host: Accept-Language: en, mi

2.1.3 请求数据

总体实例:

POST /test HTTP/2.0User-Agent: curl/7.16.3 libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3Host: Accept-Language: en, mi空行请求的数据

2.2 http响应

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

2.2.1 状态行

响应行一般由协议版本、状态码及其描述组成 比如 HTTP/1.1 200 OK

2.2.2 消息报头

消息报头用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理等一会儿它回送的数据,也是键值对的形式存在,常见有以下:

Location:这个头通常配合302或307状态码使用,服务器使用这个头告诉浏览器去找谁。Server:服务器通过这个头告诉浏览器,服务器的类型。Content-Encoding: 服务器通过这个头告诉浏览器,数据的压缩格式(gzip)。Content-Length:服务器通过这个头告诉浏览器,回送数据的长度。

2.2.3 响应正文

总体实例:

HTTP/1.1 200 OKDate: Mon, 27 Jul 12:28:53 GMTServer: ApacheLast-Modified: Wed, 22 Jul 19:15:56 GMTETag: "34aa387-d-1568eb00"Accept-Ranges: bytesContent-Length: 51Vary: Accept-EncodingContent-Type: text/plain响应正文

3. 代码分析(可在arm平台中直接使用,全c实现)

基于tcp协议的代码基于http协议代码,包括http get请求,post请求,和文件上传三种

3.1 tcp基于协议代码

/************************************************************************** @Descripttion: * @Version: 0.0.1* @Author: Xiaofang* @Date: -08-26 19:14:03* @LastEditors: Xiaofang* @LastEditTime: -09-02 23:58:12*************************************************************************/#include <stdio.h>#include <string.h>#include <stdlib.h>#include "tcp.h"#if defined(LINUX)#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <unistd.h>#include <fcntl.h>#include <errno.h>#elif defined(ARM)/*填写ARM相关的socket头文件*/#endif/*** @name: create_socket* @description: 创建socket* @note* @return 套接字 */int create_socket(void){int mysfd = socket(AF_INET, SOCK_STREAM, 0); if(mysfd < 0){printf("create_socket error = %d\r\n", mysfd);return ERROR;}return mysfd;}/*** @name: create_connect* @description: Tcp连接* @note: 传入的必须为ip,没有做域名解析* @param sockfd :网络套接字* @param host :ip* @param port :端口* @param timeout :超时时间,按照秒进行计算* @return -1:错误 -2超时 大于0正常*/int create_connect(int sockfd, char *host, int port, int stimeout){struct sockaddr_in sAddr;struct timeval timeout;fd_set fdr, fdw; int rc;int flags;// 设置非阻塞flags = fcntl(sockfd, F_GETFL, 0);if(flags < 0){printf("Get flags error:%d\n", errno);return ERROR;}flags |= O_NONBLOCK;if(fcntl(sockfd, F_SETFL, flags) < 0){printf("Set flags error:%d\n", errno);return ERROR;}//建立连接memset(&sAddr, 0, sizeof(struct sockaddr));sAddr.sin_family = AF_INET;sAddr.sin_port = htons(port);sAddr.sin_addr.s_addr= inet_addr(host);// 客户端连接,如果大于0表示已经连接成功了,此时不需要做超时判断rc = connect(sockfd, (struct sockaddr *)&sAddr, sizeof(sAddr));if(rc >= 0){goto SUCCESS;}else{if(errno == EINPROGRESS){FD_ZERO(&fdr);FD_ZERO(&fdw);FD_SET(sockfd, &fdr);FD_SET(sockfd, &fdw);timeout.tv_sec = stimeout; //通常设置为3timeout.tv_usec = 0;rc = select(sockfd+1, &fdr, &fdw, NULL, &timeout);if(rc > 0){//判断套接字是否可读if(!FD_ISSET(sockfd, &fdr) && FD_ISSET(sockfd, &fdw)){//printf("http connect ok\r\n");goto SUCCESS;}else if(FD_ISSET(sockfd, &fdr) && FD_ISSET(sockfd, &fdw)){socklen_t len = sizeof(rc);if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &rc, &len) < 0){printf("getsockopt error\r\n");return ERROR;}if(rc == 0){goto SUCCESS; }else{ printf("http timeout,rc:%d\r\n", rc);return TIMEOUT;}} }else if(rc == 0){//返回-2代表连接超时printf("http connect timeout\r\n");return TIMEOUT;}else{printf("http select error\r\n");return ERROR;}}}SUCCESS: //设置套接字为阻塞flags = fcntl(sockfd, F_GETFL, 0);if(flags < 0){printf("Get flags error:%d\n", errno);return ERROR;}flags &= ~O_NONBLOCK;if(fcntl(sockfd, F_SETFL, flags) < 0){printf("Set flags error:%d\n", errno);return ERROR;} return rc;}/*** @name: socket_send* @description: tcp支持发送超时* @note: * @param sockfd : socket 套接字* @param data : 需要发送的数据* @param len : 需要发送数据的长度* @param s : 设置超时时间按秒* @param us : 设置超时时间按微秒* @return 发送了多少个字节*/int socket_send(int sockfd, char *data, int len, int s, int us){//传参判断int rc = 0;fd_set write_fds;struct timeval timeout;timeout.tv_sec = s;timeout.tv_usec = us; FD_ZERO(&write_fds);FD_SET(sockfd, &write_fds);rc = select(sockfd+1, NULL, &write_fds, NULL, &timeout);if(rc < 0){printf("send select error %d\n", rc);return ERROR;}if(rc == 0){printf("send select timeout\n");return TIMEOUT;}if(rc > 0){if(FD_ISSET(sockfd, &write_fds)){rc = send(sockfd, data, len, 0);if(rc < 0){printf("socket send error %d\n", rc);return ERROR;}}else{printf("FD_ISSET error\n");return ERROR; }}return rc;}/*** @name: socket_recv* @description: tcp支持接收超时* @note: * @param sockfd : socket 套接字* @param data : 接收数据的缓冲区* @param len : 接收数据缓冲区的长度* @param s : 设置超时时间按秒* @param us : 设置超时时间按微秒* @return {type} */int socket_recv(int sockfd, char *response, int len ,int s, int us){int rc = 0;fd_set read_fds;struct timeval timeout;FD_ZERO(&read_fds);FD_SET(sockfd, &read_fds);timeout.tv_sec = s;timeout.tv_usec = us; rc = select(sockfd+1, &read_fds, NULL, NULL, &timeout);if(rc < 0){printf("recv select error\n");return ERROR;}if(rc == 0){printf("recv select timeout\n");return TIMEOUT;}if(rc > 0){if(FD_ISSET(sockfd, &read_fds)){rc = recv(sockfd, response, len, 0);if(rc < 0){printf("recv error %d\n",rc);return ERROR;}}else{printf("FD_ISSET error\n");return ERROR; }}return rc;}

#ifndef __TCP_H__#define __TCP_H__/**************************Macro definition***********************************//*宏开关,如果是linux平台,定义linux,否则定义ARM*/#define LINUX//#define ARMtypedef enum{TIMEOUT = -2, //超时ERROR = -1, //错误NORMAL = 0 //正常}HttpState_e;/*************************extern declaration ********************************//**************************Global variable***********************************//**************************Function declaration******************************//*** @name: create_socket* @description: 创建socket* @note* @return 套接字 */int create_socket(void);/*** @name: create_connect* @description: Tcp连接* @note: 传入的必须为ip,没有做域名解析* @param sockfd :网络套接字* @param host :ip* @param port :端口* @param timeout :超时时间,按照秒进行计算* @return -1:错误 -2超时 大于0正常*/int create_connect(int sockfd, char *host, int port, int stimeout);/*** @name: socket_send* @description: tcp支持发送超时* @note: * @param sockfd : socket 套接字* @param data : 需要发送的数据* @param len : 需要发送数据的长度* @param s : 设置超时时间按秒* @param us : 设置超时时间按微秒* @return 发送了多少个字节*/int socket_send(int sockfd, char *data, int len, int s, int us);/*** @name: socket_recv* @description: tcp支持接收超时* @note: * @param sockfd : socket 套接字* @param data : 接收数据的缓冲区* @param len : 接收数据缓冲区的长度* @param s : 设置超时时间按秒* @param us : 设置超时时间按微秒* @return {type} */int socket_recv(int sockfd, char *response, int len ,int s, int us);#endif

3.2 基于http协议代码和测试用例

/************************************************************************** @Descripttion: * @Version: * @Author: Xiaofang* @Date: -09-02 23:51:06* @LastEditors: Xiaofang* @LastEditTime: -09-03 00:00:58*************************************************************************/#include <stdio.h>#include <string.h>#include <stdlib.h>#include <sys/time.h> #include <sys/stat.h>#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h>#include "http.h"#include "tcp.h"int makehttprotocol(HttpParam_t httpparam, char *httppack){char header[MAX_SIZE_HEARER] = {0}; //需要异常判断大小char startmsg[128] = {0}; char endmsg[128] = {0};char request[256] = {0}; unsigned char http_boundary[64]={0};int startboundarylen;int endboundarylen;int requelen;int Content_Length;int headerlen;int tolsize;if(httpparam.method == GET){if(httpparam.url == NULL){sprintf(httppack, "GET / %s\r\n", HTTP1_1); }else{ sprintf(httppack, "GET %s %s\r\n", httpparam.url, HTTP1_1); }//请求头: HTTP_DEFAULT_HEADERsprintf(httppack, "%s%s\r\n",httppack, HTTP_DEFAULT_HEADER);headerlen = sprintf(httppack, "%sHost: %s:%d\r\n",httppack, httpparam.host, httpparam.port);if(httpparam.content != NULL){sprintf(httppack, "%sContent-Length: %ld\r\n\r\n", httppack, httpparam.picparm.picsize);}else{sprintf(httppack, "%s\r\n", httppack);}return httpparam.picparm.picsize+headerlen;}else if(httpparam.method == POST){if(httpparam.ispostpic == 0) //不上传图片,只是简单的post数据{if(httpparam.url == NULL){sprintf(httppack, "POST / %s\r\n", HTTP1_1);}else{sprintf(httppack, "POST %s %s\r\n", httpparam.url, HTTP1_1); }//请求头: HTTP_DEFAULT_HEADERsprintf(httppack, "%s%s\r\n",httppack, HTTP_DEFAULT_HEADER);headerlen = sprintf(httppack, "%sHost: %s:%d\r\n",httppack, httpparam.host, httpparam.port);if(httpparam.content != NULL){sprintf(httppack, "%sContent-Length: %ld\r\n\r\n", httppack, httpparam.picparm.picsize);}else{sprintf(httppack, "%s\r\n", httppack);}sprintf(httppack, "%s%s\r\n", httppack, httpparam.content);return httpparam.picparm.picsize+headerlen;}else if(httpparam.ispostpic == 1) //上传图片{long long int timestamp;struct timeval tv;gettimeofday(&tv,NULL);timestamp = (long long int)tv.tv_sec * 1000 + tv.tv_usec;//1. 获取http_boundarysprintf(http_boundary,"----------------------------%lld",timestamp);//2. start boundarystartboundarylen = sprintf(startmsg, "--%s\r\n",http_boundary);//3. end boundartendboundarylen = sprintf(endmsg, "\r\n--%s--\r\n",http_boundary);//4. int requelen = sprintf(request, UPLOAD_REQUEST, httpparam.picparm.picname);int Content_Length = requelen + startboundarylen + httpparam.picparm.picsize + endboundarylen;int headerlen = sprintf(header, HTTP_POST_PIC_HEAD, httpparam.url, httpparam.host, http_boundary, Content_Length);int tolsize = Content_Length + strlen(HTTP_POST_PIC_HEAD) + 256; //加256防止溢出memcpy(httppack, header, headerlen);memcpy(httppack+headerlen, startmsg, startboundarylen);memcpy(httppack+headerlen+startboundarylen, request, requelen);memcpy(httppack+headerlen+startboundarylen+requelen, httpparam.content, httpparam.picparm.picsize);memcpy(httppack+headerlen+startboundarylen+requelen+httpparam.picparm.picsize, endmsg, endboundarylen);return tolsize;}}return 0;}/*** @name: http_post* @description: 实现http post和get的请求* @note: * @param httpparam:http参数结构体* @param content:post的内容* @param len:内容的长度* @param response:获得的响应内容* @param resplen:需要获取响应内容大小* @return -1错误 -2超时*/int http(HttpParam_t httpparam, char *content, int len, char *response, int resplen){int rc=0;int httpfp=0;char *httppack;httppack = malloc(len+512); //假设http头长度有512,http上传的最终头memset(httppack, 0, sizeof(len+512));httpfp = create_socket();if(httpfp < 0){free(httppack);return ERROR;}rc = create_connect(httpfp, httpparam.host, httpparam.port, CONNECTTIMEOUT);if(rc < 0){free(httppack);return rc;}rc = makehttprotocol(httpparam, httppack);if(rc < 0){free(httppack);return rc;}rc = socket_send(httpfp, httppack, rc, httpparam.timeouts, httpparam.timeoutus);if(rc < 0){free(httppack);return rc;}//此处存在接收不到的情况,可以通过多线程解决,不断的接收数据rc = socket_recv(httpfp, response, resplen , httpparam.timeouts, httpparam.timeoutus);if(rc < 0){free(httppack);return rc;}printf("response = %s\n",response);free(httppack);return 0;}int http_responed(char *respsone){if(respsone == NULL){return -1;}//1. 判断返回值中是否有200int code;char *resp;resp = strstr(respsone , "\r\n\r\n");resp += 4;//2. 再获取其返回值内容//printf("%s\n", resp);/*cJSON *root = cJSON_Parse(resp);if(root == NULL){printf("http respsone is null\n");}cJSON *pos;pos = cJSON_GetObjectItem(root, "code");if(pos != NULL){code= (pos->valueint);}else{cJSON_Delete(root);return -1;}if(code == 0){cJSON_Delete(root);return -1;}cJSON_Delete(root);*/return 0;}int main(){HttpParam_t httpparam;char responed[1024] = {0};memset(httpparam.host, 0, sizeof(httpparam.host));memset(httpparam.url, 0, sizeof(httpparam.url));strcpy(httpparam.host, "172.16.62.147");strcpy(httpparam.url, "/lift/api/uploadFaultPic?id=123123123123 "); //后面的id是我们项目所需要的参数strcpy(httpparam.picparm.picname , "123.png");httpparam.ispostpic = 1;httpparam.port = 80;httpparam.method = POST;httpparam.timeouts = 1;httpparam.timeoutus = 0;FILE* fp = fopen("123.png", "rb+");//打开要上传的图片if (fp == NULL){ printf("open file fail!\r\n"); return -1; }fseek(fp, 0, SEEK_END);httpparam.picparm.picsize = ftell(fp);rewind(fp);printf("get the size is: %ld\n", httpparam.picparm.picsize);httpparam.content = malloc(httpparam.picparm.picsize);memset(httpparam.content, 0, sizeof(httpparam.picparm.picsize));fread(httpparam.content, httpparam.picparm.picsize, 1, fp);int re = http(httpparam, httpparam.content, httpparam.picparm.picsize, responed, 1024);free(httpparam.content);//printf("%s\n",content);}

/** @Descripttion: * @Version: * @Author: Xiaofang* @Date: -09-02 23:51:17* @LastEditors: Xiaofang* @LastEditTime: -09-02 23:55:21*/#ifndef __HTTP_H__#define __HTTP_H__#define CONNECTTIMEOUT 3#define MAX_SIZE_HEARER 2048//http版本#define HTTP1_1 "HTTP/1.1"#define HTTP2_0 "HTTP/2.0"//hear普通头#define HTTP_DEFAULT_HEADER "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:63.0) Gecko/0101 Firefox/63.0\r\n" \"Connection: keep-alive\r\n" \"Cache-Control: no-cache\r\n" \"Content-Type: application/json\r\n" \"Accept: */*"//http上传文件所需要的头//"enctype: multipart/form-data\r\n"#define HTTP_POST_PIC_HEAD "POST %s HTTP/1.1\r\n"\"User-Agent: PostmanRuntime/7.24.1\r\n"\"Accept: */*\r\n"\"Host: %s\r\n"\"Accept-Encoding: gzip, deflate, br\r\n" \"Connection: keep-alive\r\n" \"Content-Type: multipart/form-data; boundary=%s\r\n"\"Content-Length: %d\r\n\r\n"\#define UPLOAD_REQUEST"Content-Disposition: form-data; name=\"file\"; filename=\"%s\"\r\n" \"Content-Type: image/png\r\n\r\n"/**************************Type definition **********************************///请求方式typedef enum {GET,POST}RequestMethod_e;typedef struct {char picname[32];unsigned long picsize;}PicParm_t;typedef struct{char host[16];char url[128]; //包含参数,参数从url中传入int ispostpic; //是否需要上传图片int port;int method;int timeouts;int timeoutus;char *content; //需要申请空间,存放数据PicParm_t picparm; //图片参数}HttpParam_t;/**************************Function declaration******************************/int makehttprotocol(HttpParam_t httpparam, char *httppack);/*** @name: http_post* @description: 实现http post和get的请求* @note: * @param httpparam:http参数结构体* @param content:post的内容* @param len:内容的长度* @param response:获得的响应内容* @param resplen:需要获取响应内容大小* @return -1错误 -2超时*/int http(HttpParam_t httpparam, char *content, int len, char *response, int resplen);#endif

如果觉得《C语言实现http post请求和get请求 post请求可以上传图片和文件》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。