Linux C 实现HTTP的增删改查(GET POST PUT DELETE)

Linux C 实现HTTP的增删改查(GET POST PUT DELETE)


全部代码

//http.h文件
#ifndef _MY_HTTP_H
#define _MY_HTTP_H
 
#define MY_HTTP_DEFAULT_PORT 80
 
char * http_get(const char *url);
char * http_post(const char *url,const char * post_str);
char * http_delete(const char *url);
char * http_put(const char *url,const char * post_str);
 
#endif
//http.c文件
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <string.h>
 
#include "http.h"

#define BUFFER_SIZE 1024
#define HTTP_POST "POST /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\nContent-Type:application/json\r\nContent-Length: %d\r\n\r\n%s"
#define HTTP_GET "GET /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\n\r\n"
#define HTTP_PUT "PUT /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\nContent-Type:application/json\r\nContent-Length: %d\r\n\r\n%s"
#define HTTP_DELETE "DELETE /%s HTTP/1.1\r\nHOST: %s:%d\r\nAccept: */*\r\n\r\n"
  
static int http_tcpclient_create(const char *host, int port){
    struct hostent *he;
    struct sockaddr_in server_addr; 
    int socket_fd;
 
    if((he = gethostbyname(host))==NULL){
        return -1;
    }
 
   server_addr.sin_family = AF_INET;
   server_addr.sin_port = htons(port);
   server_addr.sin_addr = *((struct in_addr *)he->h_addr);   
 
    if((socket_fd = socket(AF_INET,SOCK_STREAM,0))==-1){
        return -1;
    }
 
    if(connect(socket_fd, (struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1){
        return -1;
    }
 
    return socket_fd;
}
 
static void http_tcpclient_close(int socket){
    close(socket);
}

static int http_parse_url(const char *url,char *host,char *file,int *port) //分析url 
{
    char *ptr1,*ptr2;
    int len = 0;
    if(!url || !host || !file || !port){
        return -1;
    }
    ptr1 = (char *)url;    //如果是"http://127.0.0.1:8080/1213 
    if(!strncmp(ptr1,"http://",strlen("http://"))){
        ptr1 += strlen("http://");     //移动指针到 "http://"的后面 (127.0.0.1:8080/1213)
    }else{
        return -1;
    }
    ptr2 = strchr(ptr1,'/');   //(/1213)
    if(ptr2){
        len = strlen(ptr1) - strlen(ptr2);
        memcpy(host,ptr1,len);
        host[len] = '\0';    //(127.0.0.1:8080)
        if(*(ptr2 + 1)){     //移动指针 (1213)
            memcpy(file,ptr2 + 1,strlen(ptr2) - 1 );
            file[strlen(ptr2) - 1] = '\0';
        }
    }else{
        memcpy(host,ptr1,strlen(ptr1));
        host[strlen(ptr1)] = '\0';
    }
    //get host and ip
    ptr1 = strchr(host,':');    //(8080)
    if(ptr1){
        *ptr1++ = '\0';
        *port = atoi(ptr1);
    }else{
        *port = MY_HTTP_DEFAULT_PORT;
    }
    return 0;
 }

static int http_tcpclient_recv(int socket,char *lpbuff){ //不论是客户还是服务器应用程序都用recv函数从TCP连接的另一端接收数据
    int recvnum = 0;
    recvnum = recv(socket, lpbuff,BUFFER_SIZE*4,0);  //lpbuff(指明一个缓冲区,该缓冲区用来存放recv函数接收到的数据)
    lpbuff[recvnum] = 0;  //这里需要加个终止符,因为lpbuff是每一次请求中至始至终使用的缓冲区,没有加终止符的话,会导致接收到的数据残留一些上一次接收的
    return recvnum;
}
 
static int http_tcpclient_send(int socket,char *buff,int size){  //发送数据 
    int sent=0,tmpres=0;
    while(sent < size){
        tmpres = send(socket,buff+sent,size-sent,0);
        if(tmpres == -1){
            return -1;
        }
        sent += tmpres;
    }
    return sent;
}
 
static char *http_parse_result(const char*lpbuf){  //处理响应报文 
    char *ptmp = NULL; 
    char *response = NULL;
    ptmp = (char*)strstr(lpbuf,"HTTP/1.1");
    if(!ptmp){
        printf("http/1.1 not faind\n");
        return NULL;
    }
    if(atoi(ptmp + 9)!=200){   //atoi把字符串转换为整数 //移动ptmp的指针,得到状态码,状态码为200的话表示成功 
        printf("result:\n%s\n",lpbuf);     
        return NULL;
    }
    ptmp = (char*)strstr(lpbuf,"\r\n\r\n");
    if(!ptmp){
        printf("ptmp is NULL\n");
        return NULL;
    }
    response = (char *)malloc(strlen(ptmp)+1);    //记住malloc出来的堆空间要free,一次malloc一次free,否则会内存泄露,free可以在调用的函数那里再free
    if(!response){
        printf("malloc failed \n");
        return NULL;
    }
    strcpy(response,ptmp+4);
    return response;
}

char * http_post(const char *url,const char *post_str){  //处理post请求 
    char post[BUFFER_SIZE] = {'\0'};
    int socket_fd = -1;
    char lpbuf[BUFFER_SIZE*4] = {'\0'};
    char *ptmp;
    char host_addr[BUFFER_SIZE] = {'\0'};
    char file[BUFFER_SIZE] = {'\0'};
    int port = 0;
    int len=0;
	char *response = NULL;
    if(!url || !post_str){
        printf("      failed!\n");		
        return NULL;
    }
    if(http_parse_url(url,host_addr,file,&port)<0){    
        printf("http_parse_url failed!\n");
        return NULL;
    }
   // printf("host_addr : %s\tfile:%s\t,%d\n",host_addr,file,port);
    socket_fd = http_tcpclient_create(host_addr,port);
    if(socket_fd < 0){
        printf("http_tcpclient_create failed\n");
        return NULL;
    }
                                     
    sprintf(lpbuf,HTTP_POST,file,host_addr,port,strlen(post_str),post_str);
                                          	
    if(http_tcpclient_send(socket_fd,lpbuf,strlen(lpbuf)) < 0){
        printf("http_tcpclient_send failed..\n");
        http_tcpclient_close(socket_fd); //当文件描述符创建成功后,都要close,不然文件描述符有可能会用尽
        return NULL;
    }
	//printf("发送请求:\n%s\n",lpbuf);
            	 
    /*it's time to recv from server*/
    if(http_tcpclient_recv(socket_fd,lpbuf) <= 0){
        printf("http_tcpclient_recv failed\n");
        http_tcpclient_close(socket_fd);
        return NULL;
    }
                                      	                        	                              
    http_tcpclient_close(socket_fd);
    return http_parse_result(lpbuf);
}

char * http_put(const char *url,const char *post_str){  //处理put请求 
    char post[BUFFER_SIZE] = {'\0'};
    int socket_fd = -1;
    char lpbuf[BUFFER_SIZE*4] = {'\0'};
    char *ptmp;
    char host_addr[BUFFER_SIZE] = {'\0'};
    char file[BUFFER_SIZE] = {'\0'};
    int port = 0;
    int len=0;
	char *response = NULL;
    if(!url || !post_str){
        printf("      failed!\n");		
        return NULL;
    }
    if(http_parse_url(url,host_addr,file,&port)<0){    
        printf("http_parse_url failed!\n");
        return NULL;
    }
   // printf("host_addr : %s\tfile:%s\t,%d\n",host_addr,file,port);
    socket_fd = http_tcpclient_create(host_addr,port);
    if(socket_fd < 0){
        printf("http_tcpclient_create failed\n");
        return NULL;
    }
                                     
    sprintf(lpbuf,HTTP_PUT,file,host_addr,port,strlen(post_str),post_str);
                                          	
    if(http_tcpclient_send(socket_fd,lpbuf,strlen(lpbuf)) < 0){
        printf("http_tcpclient_send failed..\n");
        return NULL;
    }
	//printf("发送请求:\n%s\n",lpbuf);
            	 
    /*it's time to recv from server*/
    if(http_tcpclient_recv(socket_fd,lpbuf) <= 0){
        printf("http_tcpclient_recv failed\n");
        return NULL;
    }
                                      	                        	                              
    http_tcpclient_close(socket_fd);
    return http_parse_result(lpbuf);
}

char * http_get(const char *url)    //处理get请求 
{
    char post[BUFFER_SIZE] = {'\0'};
    int socket_fd = -1;
    char lpbuf[BUFFER_SIZE*4] = {'\0'};
    char *ptmp;
    char host_addr[BUFFER_SIZE] = {'\0'};
    char file[BUFFER_SIZE] = {'\0'};
    int port = 0;
    int len=0;
    if(!url){
        printf("      failed!\n");
        return NULL;
    }
    if(http_parse_url(url,host_addr,file,&port)<0){
        printf("http_parse_url failed!\n");
        return NULL;
    }
    //printf("host_addr : %s\tfile:%s\t,%d\n",host_addr,file,port);
    socket_fd =  http_tcpclient_create(host_addr,port);
    if(socket_fd < 0){
        printf("http_tcpclient_create failed\n");
        return NULL;
    }
 
    sprintf(lpbuf,HTTP_GET,file,host_addr,port);
 
    if(http_tcpclient_send(socket_fd,lpbuf,strlen(lpbuf)) < 0){
        printf("http_tcpclient_send failed..\n");
        return NULL;
    }
//	printf("发送请求:\n%s\n",lpbuf);
    if(http_tcpclient_recv(socket_fd,lpbuf) <= 0){
        printf("http_tcpclient_recv failed\n");
        return NULL;
    }
    http_tcpclient_close(socket_fd);
    return http_parse_result(lpbuf);
}

char * http_delete(const char *url)    //处理delete请求 
{
    char post[BUFFER_SIZE] = {'\0'};
    int socket_fd = -1;
    char lpbuf[BUFFER_SIZE*4] = {'\0'};
    char *ptmp;
    char host_addr[BUFFER_SIZE] = {'\0'};
    char file[BUFFER_SIZE] = {'\0'};
    int port = 0;
    int len=0;
    if(!url){
        printf("      failed!\n");
        return NULL;
    }
    if(http_parse_url(url,host_addr,file,&port)<0){
        printf("http_parse_url failed!\n");
        return NULL;
    }
    //printf("host_addr : %s\tfile:%s\t,%d\n",host_addr,file,port);
    socket_fd =  http_tcpclient_create(host_addr,port);
    if(socket_fd < 0){
        printf("http_tcpclient_create failed\n");
        return NULL;
    }
 
    sprintf(lpbuf,HTTP_DELETE,file,host_addr,port);
 
    if(http_tcpclient_send(socket_fd,lpbuf,strlen(lpbuf)) < 0){
        printf("http_tcpclient_send failed..\n");
        return NULL;
    }
//	printf("发送请求:\n%s\n",lpbuf);
    if(http_tcpclient_recv(socket_fd,lpbuf) <= 0){
        printf("http_tcpclient_recv failed\n");
        return NULL;
    }
    http_tcpclient_close(socket_fd);
    return http_parse_result(lpbuf);
}
int main()   //用了自己的项目做测试
{
	char * result = NULL;
	char * send = "{\"name\": \"老王\",\"getCash\": 0.0,\"aopenid\": \"sssssss\",\"aid\": 1,\"phone\": \"15914716715\"}";     
	//注意json文件定义成字符串时,引号前面要加转义符。而且这里要写出一行,不然也会出错。具体原因我也还不知道。
//	result = http_get("http://192.168.1.101:18081/admin/1");
//	result = http_delete("http://192.168.1.101:18081/admin/3");
//    result = http_post("http://192.168.1.101:18081/admin",send);
	result = http_put("http://192.168.1.101:18081/admin/1",send);
	printf("%s",result);
	return 0;
}

HTTP请求报文的格式
在这里插入图片描述
主要由请求行、请求头部、空行、请求数据组成。
请求行:由3部分组成,分别为:请求方法(GET、POST、PUT等)、URL以及协议版本(协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1),每两个之间由空格分隔。
请求头部:包含很多客户端环境以及请求正文的有用信息。请求头部由“关键字:值”对组成,每行一堆,关键字和值之间使用英文“:”分隔。
空行:注意这个是必不可少的,是固定格式。表示请求头部结束
请求正文:可选部分,比如GET请求就没有请求正文;POST比如以提交表单数据方式为请求正文。

如本代码的测试结果:
GET的请求报文
GET的请求报文
POST的请求报文
在这里插入图片描述
HTTP的响应报文格式
在这里插入图片描述
主要由状态行、响应头部、空行和响应正文组成。
状态行:由3部分组成,分别为:协议版本,状态码,状态码描述,每两个之间由空格分隔。状态代码为3位数字,200-299的状态码表示成功,300-399的状态码指资源重定向,400-499的状态码指客户端请求出错,500-599的状态码指服务端出错(HTTP/1.1向协议中引入了信息性状态码,范围为100-199)。
响应头部:与请求头部类似,也包含了很多有用的信息。
空行:这一行必不可少。表示响应头部结束。
响应正文:服务器返回的文档,最常见的为HTML网页。

不过本代码返回的是json文件。
POST的响应报文:
在这里插入图片描述
总结:四种请求需要的处理(socket的创建、请求报文的发送、url的分析、响应报文的接收、响应报文的处理以及socket的关闭)的代码都是一样的,只是各自请求内部的操作有所不同。
关于HTTP报文格式的可以参考:https://www.cnblogs.com/weibanggang/p/9454581.html
https://blog.csdn.net/weixin_39945445/article/details/112090690
有错误的地方还请斧正!
还有本文章是我参考网上的资料整理的,有所冒犯,还请作者联系我。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值