c语言——http编程

2023-05-16

HTTP协议简介

  • 超文本传输协议是一种用于分布式、协作式和超媒体信息系统的应用层协议。
  • HTTP是一个客户端终端(用户)和服务器端(网站)请求和应答的标准(一般基于TCP)。客户端发起一个HTTP请求到服务器上指定端口(默认端口为80),这个客户端被称为用户代理程序(user agent)。应答服务器被称为源服务器(origin server)。在用户代理和源服务器中间可能存在多个“中间层”,比如代理服务器、网关或者隧道(tunnel)
  • HTTP可以在任何互联网协议上,或其他网络上实现。HTTP假定其下层协议提供可靠的传输。任何能够提供这种保证的协议都可以被其使用
  • 由HTTP客户端发起一个请求,创建一个到服务器指定端口(默认是80端口)的TCP连接。HTTP服务器则在那个端口监听客户端的请求。一旦收到请求,服务器会向客户端返回一个状态,比如"HTTP/1.1 200 OK",以及返回的内容,如请求的文件、错误消息、或者其它信息。

HTTP工作原理

HTTP协议定义Web客户端如何从Web服务器请求Web页面,以及服务器如何把Web页面传送给客户端。HTTP协议采用了请求/响应模型。客户端向服务器发送一个请求报文,请求报文包含请求的方法、URL、协议版本、请求头部和请求数据。服务器以一个状态行作为响应,响应的内容包括协议的版本、成功或者错误代码、服务器信息、响应头部和响应数据。

  1. 客户端——发出连接服务器请求
  2. 客户端——发送HTTP请求
    通过TCP套接字,客户端向Web服务器发送一个文本的请求报文,一个请求报文由请求行、请求头部、空行和请求数据4部分组成。
  3. 服务器——服务器接受请求并返回HTTP响应
    一个响应由状态行、响应头部、空行和响应数据4部分组成。
  4. 服务器——释放连接TCP连接
    若connection 模式为close,则服务器主动关闭TCP连接,客户端被动关闭连接,释放TCP连接;若connection 模式为keepalive,则该连接会保持一段时间,在该时间内可以继续接收请求
  5. 客户端——解析反馈的内容

一次http请求之后,http协议1.1版本不会直接就断开了,而是等几秒钟,等着用户有后续的操作,如果用户在这几秒钟之内有新的请求,那么还是通过之前的连接通道来收发消息,如果过了这几秒钟用户没有发送新的请求,那么就会断开连接,这样可以提高效率,减少短时间内建立连接的次数,因为建立连接也是耗时的,默认的好像是3秒中现在,但是这个时间是可以通过咱们后端的代码来调整的,自己网站根据自己网站用户的行为来分析统计出一个最优的等待时间。

HTTP请求方式

  1. OPTIONS
    返回服务器针对特定资源所支持的HTTP请求方法,也可以利用向web服务器发送‘*’的请求来测试服务器的功能性
  2. HEAD
    向服务器索与GET请求相一致的响应,只不过响应体将不会被返回。用于获取报文头
  3. GET
    向特定的资源发出请求。注意:GET方法不应当被用于产生“副作用”的操作中,例如在Web Application中,其中一个原因是GET可能会被网络蜘蛛等随意访问。
  4. POST
    向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
  5. PUT
    向指定资源位置上传其最新内容
  6. DELETE
    请求服务器删除Request-URL所标识的资源
  7. TRACE
    回显服务器收到的请求,主要用于测试或诊断
  8. CONNECT
    HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。

GET与POST方法区别

  • 在客户端,Get方式在通过URL提交数据,数据在URL中可以看到;POST方式,数据放置在HTML HEADER内提交
  • GET方式提交的数据最多只能有1024字节,而POST则没有此限制
  • 使用 Get 的时候,参数会显示在地址栏上,而 Post 不会。如果这些数据是中文数据而且是非敏感数据,那么使用 get;如果用户输入的数据不是中文字符而且包含敏感数据,那么还是使用 post为好。

HTTP状态码

状态代码的第一个数字代表当前响应的类型:

  • 1xx消息——请求已被服务器接收,继续处理
  • 2xx成功——请求已成功被服务器接收、理解、并接受
  • 3xx重定向——需要后续操作才能完成这一请求
  • 4xx请求错误——请求含有词法错误或者无法被执行
  • 5xx服务器错误——服务器在处理某个正确请求时发生错误

URL解析

超文本传输协议(HTTP)的统一资源定位符将从因特网获取信息的五个基本元素包括在一个简单的地址中:

  • 传送协议。层级URL标记符号(为[//],固定不变)
  • 服务器。(通常为域名,有时为IP地址)
  • 端口号。(以数字方式表示,若为HTTP的默认值“:80”可省略)
  • 路径。(以“/”字符区别路径中的每一个目录名称)
  • 查询。(GET模式的窗体参数,以“?”字符为起点,每个参数以“&”隔开,再以“=”分开参数名称与数据,通常以UTF8的URL编码,避开字符冲突的问题)片段。以“#”字符为起点

例子:
以http://www.luffycity.com:80/news/index.html?id=250&page=1 为例, 其中:
http,是协议;
www.luffycity.com,是服务器
80,是服务器上的默认网络端口号
?id=250&page=1,是查询数据

找了一个基于TCP协议,实现HTTP传输的code,修改一下生成一个测试demo:

my_tcpclient.c

#include "my_tcpclient.h"

int main(){

    my_tcpclient client;
	int flags = 1;

    char *response = NULL;
    printf("开始组包\n");

	while(flags){
		my_tcpclient_create(&client,"10.100.10.24",18080);
		if(http_post(&client,"/esim-lpa-server/lpa/polling?","data=89086030202200000019000037012045",&response)){
	        printf("失败!\n");
	        exit(2);
	    }
	    printf("响应:\n%d:%s\n",strlen(response),response);
		flags = 0;
	}

    free(response);
    return 0;
}

my_tcpclient.h

#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>  
#include <sys/socket.h>

#define __DEBUG

#ifdef __DEBUG
#define DEBUG(...)	printf(__VA_ARGS__)
#else
#define DEBUG(...)
#endif


#define BUFFER_SIZE 1024

/*
	@socket
	@remote_port
	@remote_ip
	@sockaddr_in
	@connected flag
*/
typedef struct _my_tcpclient{
    int socket;
    int remote_port;     
    char remote_ip[16];  
    struct sockaddr_in _addr; 
    int connected;       
} my_tcpclient;

int my_tcpclient_create(my_tcpclient *pclient,const char *host, int port);
int my_tcpclient_conn(my_tcpclient *pclient);
int my_tcpclient_recv(my_tcpclient *pclient,char **lpbuff,int size);
int my_tcpclient_send(my_tcpclient *pclient,char *buff,int size);
int my_tcpclient_close(my_tcpclient *pclient);
int my_http_post(my_tcpclient *pclient,char *page,char *request,char **response);


int my_tcpclient_create(my_tcpclient *pclient,const char *host, int port){
    struct hostent *he;

    if(pclient == NULL) 
		return -1;

    memset(pclient,0,sizeof(my_tcpclient));

    if((he = gethostbyname(host))==NULL){
        return -2;
    }

    pclient->remote_port = port;
    strcpy(pclient->remote_ip,inet_ntoa( *((struct in_addr *)he->h_addr) ));

    pclient->_addr.sin_family = AF_INET;
    pclient->_addr.sin_port = htons(pclient->remote_port);
    pclient->_addr.sin_addr = *((struct in_addr *)he->h_addr);

    if((pclient->socket = socket(AF_INET,SOCK_STREAM,0))==-1){
        return -3;
    }

    return 0;
}

int my_tcpclient_conn(my_tcpclient *pclient){

    if(pclient->connected)
        return 1;

    if(connect(pclient->socket, (struct sockaddr *)&pclient->_addr,sizeof(struct sockaddr))==-1){
        return -1;
    }

    pclient->connected = 1;

    return 0;
}

int my_tcpclient_recv(my_tcpclient *pclient,char **lpbuff,int size){
    int recvnum=0,tmpres=0;
    char buff[BUFFER_SIZE];

    *lpbuff = NULL;

    while(recvnum < size || size==0){
        tmpres = recv(pclient->socket, buff,BUFFER_SIZE,0);
        if(tmpres <= 0)
            break;
        recvnum += tmpres;

        if(*lpbuff == NULL){
            *lpbuff = (char*)malloc(recvnum);
            if(*lpbuff == NULL)
                return -2;
        }else{
            *lpbuff = (char*)realloc(*lpbuff,recvnum);
            if(*lpbuff == NULL)
                return -2;
        }

        memcpy(*lpbuff+recvnum-tmpres,buff,tmpres);
    }

    return recvnum;
}

int my_tcpclient_send(my_tcpclient *pclient,char *buff,int size){
    int sent=0,tmpres=0;

    while(sent < size){
        tmpres = send(pclient->socket,buff+sent,size-sent,0);
        if(tmpres == -1){
            return -1;
        }
        sent += tmpres;
    }
    return sent;
}

int my_tcpclient_close(my_tcpclient *pclient){
    close(pclient->socket);
    pclient->connected = 0;
}

void get_http_header(char *header){
	char userAgent[] = "User-Agent: QG1 Http 0.1\r\n";
	char cacheCtrl[] = "Cache-Control: no-cache\r\n";
	char contentType[] = "Content-Type: application/x-www-form-urlencoded\r\n";
	char postmanToken[] = "Postman-Token: 8d4d5783-4660-c219-8644-e2e7dad68500\r\n";
	char auth[] = "Authorization: Basic cm9hbTJmcmVlOmx5bmttYXhfdGVzdA==\r\n";
	char accept[] = "Accept: */*\r\n";

	strcpy(header,userAgent);
    strcat(header,cacheCtrl);
    strcat(header,contentType);
    strcat(header,postmanToken);
    strcat(header,auth);
	strcat(header,accept);
}

int http_post(my_tcpclient *pclient,char *page,char *request,char **response){

    char post[300],host[100],content_len[100];
    char *lpbuf,*ptmp;
    int len=0;

	char header2[1024];

	memset(header2, sizeof(header2), 0);
	get_http_header(header2);

	//DEBUG("header2 : %s \n", header2);

    lpbuf = NULL;

    sprintf(post,"POST %s HTTP/1.0\r\n",page);
    sprintf(host,"HOST: %s:%d\r\n",pclient->remote_ip,pclient->remote_port);
    sprintf(content_len,"Content-Length: %d\r\n\r\n",strlen(request));

    len = strlen(post)+strlen(host)+strlen(header2)+strlen(content_len)+strlen(request)+1;
    lpbuf = (char*)malloc(len);
    if(lpbuf==NULL){
        return -1;
    }

    strcpy(lpbuf,post);
    strcat(lpbuf,host);
    strcat(lpbuf,header2);
    strcat(lpbuf,content_len);
    strcat(lpbuf,request);

	//printf("liuyan: http data= \r\n%s liuyan end \n", lpbuf);

    if(!pclient->connected){
        my_tcpclient_conn(pclient);
    }

    if(my_tcpclient_send(pclient,lpbuf,len)<0){
        return -1;
    }
	printf("发送请求:\n%s\n",lpbuf);

    /*释放内存*/
    if(lpbuf != NULL) 
		free(lpbuf);
	
    lpbuf = NULL;

    /*it's time to recv from server*/
    if(my_tcpclient_recv(pclient,&lpbuf,0) <= 0){
        if(lpbuf) 
			free(lpbuf);
        return -2;
    }
	printf("接收响应:\n%s\n",lpbuf);

    /*响应代码,|HTTP/1.0 200 OK|
     *从第10个字符开始,第3位
     * */
    memset(post,0,sizeof(post));
    strncpy(post,lpbuf+9,3);
    if(atoi(post)!=200){
        if(lpbuf) free(lpbuf);
        return atoi(post);
    }

    ptmp = (char*)strstr(lpbuf,"\r\n\r\n");
    if(ptmp == NULL){
        free(lpbuf);
        return -3;
    }
    ptmp += 4;/*跳过\r\n*/

    len = strlen(ptmp)+1;
    *response=(char*)malloc(len);
    if(*response == NULL){
        if(lpbuf) free(lpbuf);
        return -1;
    }
    memset(*response,0,len);
    memcpy(*response,ptmp,len-1);

    /*从头域找到内容长度,如果没有找到则不处理*/
    ptmp = (char*)strstr(lpbuf,"Content-Length:");
    if(ptmp != NULL){
        char *ptmp2;
        ptmp += 15;
        ptmp2 = (char*)strstr(ptmp,"\r\n");
        if(ptmp2 != NULL){
            memset(post,0,sizeof(post));
            strncpy(post,ptmp,ptmp2-ptmp);
            if(atoi(post)<len)
                (*response)[atoi(post)] = '\0';
        }
    }

    if(lpbuf) free(lpbuf);

    return 0;
}

执行结果
使用TCP传输的打印结果
发送数据/接收数据

  1. url地址
  2. ip地址+端口号, HTTP header
  3. 发送请求
  4. 接收结果。200代表sucess
  5. 服务器端HTTP header
  6. 返回得到的结果
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

c语言——http编程 的相关文章

  • 如何为 HTTP GET 的多个 Key-Value 参数设计 REST URI

    我正在设计一个 RESTful API 一项服务应该提供多个键值对的查询功能 例如 客户端可以使用一个 HTTP GET 请求来查询不同的产品及其关联的数量 客户想要查询金额为 44 的产品 1 和金额为 55 的产品 2 我实际上不希望我
  • 如何在我的 gstreamer 中启用 httpsrc 插件?

    我尝试使用以下命令播放通过 http 检索的 mp3 文件或流 gst launch httpsrc location http domain com music mp3 mad osssink 但出现以下错误 ERREUR le pipe
  • 在 Angular 中一起使用 Promise 和服务

    我的问题是基于这个话题 https groups google com forum msg angular qagzXXhS VI p9ArYjfivW8J在 Angular 谷歌小组中 我想提供一个服务 存储通过 http 从后端检索的一
  • 在获得响应之前发出多个请求

    当并行发送多个请求时 在获得响应之前 我无法理解 HTTP 的工作原理 有两种情况 1 With Connection Keep Alive 根据HTTP规范 http www w3 org Protocols rfc2616 rfc261
  • RxJS Angular2 在 Observable.forkjoin 中处理 404

    我目前正在链接一堆 http 请求 但是在订阅之前我无法处理 404 错误 My code 在模板中 service getData subscribe data gt this items data err gt console log
  • htaccess 重定向非 www http 和 https

    我想要 http example com重定向至 http www example com https example com重定向至 https www example com 以及任何东西http whatever example co
  • 响应中的有效 JSON

    我正在开发客户端和服务器应用程序 遇到了一个有趣的问题 我们正在创建一个 Restful API 并通过 JSON 响应与客户端进行通信 执行 DELETE 时 我们将返回 200 OK 和空白响应 我们的客户收到 200 OK 但解析 J
  • 使用矩阵参数创建 GET 请求

    我将使用的网络服务需要矩阵参数 http tester com v1 customers lastname Jackson firstname Tim bookingreference 7Y9UIY 而不是通常的 http tester c
  • python http 客户端卡在 100 continue

    我在 python 中有一个简单的 http 服务器 它使用 100 continue 实现 PUT class TestHandler SimpleHTTPRequestHandler def do PUT self length int
  • 如何在 Android 中从服务器检索数据时更新滚动的 ListView?

    目前 我正在使用 AsyncTask 来处理 Http 连接并以 JSON 格式检索数据 加载所有数据很简单 但会消耗太多时间 因此我决定使用一次加载 10 个项目LIMIT OFFSET mysql 接下来我设置事件onScroll为我的
  • 如何从 Kubernetes 服务背后的 HTTP 请求读取客户端 IP 地址?

    我的 Web 应用程序作为 Kubernetes pod 在 SSL 的 nginx 反向代理后面运行 代理和我的应用程序都使用 Kubernetes 服务进行负载平衡 如所述here http blog kubernetes io 201
  • HTTP 查询字符串和 []

    PHP 使用 在查询参数名称中 以确保多次出现的参数都出现在 GET超全局变量 否则只出现最后一次出现的情况 还有其他软件可以做到这一点吗 但从RFC 3986 https www rfc editor org rfc rfc3986 以及
  • 内容长度标头与分块编码

    我正在尝试权衡设置的利弊Content LengthHTTP 标头与使用分块编码从我的服务器返回 可能 大文件的比较 使用持久连接需要其中之一来符合 HTTP 1 1 规范 我看到了的优点Content Length标头是 下载对话框可以显
  • 反向代理受 NTLM 保护的网站

    如何将请求代理到受 NTLM 保护的网站 例如团队基金会 and 共享点 我不断得到401 身份验证错误 根据这篇 Microsoft TechNet 文章 https www microsoft com technet prodtechn
  • 对过期会话进行休息调用:HTTP 401 响应导致浏览器显示登录窗口

    我编写了一个 HTML 5 应用程序 它使用 AngularJS 并与在 Tomcat 上运行的 Java REST 后端进行交互 我使用 Spring Security 来处理登录和安全性 当用户进入网站时 他将被转发到登录页面 该页面创
  • ReverseProxy取决于golang中的request.Body

    我想构建一个 http 反向代理 它检查 HTTP 主体 然后将 HTTP 请求发送到它的上游服务器 你怎么能在 Go 中做到这一点 初始尝试 如下 失败 因为 ReverseProxy 复制传入请求 修改它并发送 但正文已被读取 func
  • 减少1000张图片的HTTP请求?

    我知道这个问题可能听起来有点疯狂 但我想也许有人会想出一个聪明的主意 假设您在一个 HTML 页面上有 1000 个缩略图 图像大小约为5 10 kb 有没有办法在单个请求中加载所有图像 以某种方式将所有图像压缩到一个文件中 或者您对该主题
  • 使用 Google OAuth2.0 时出现错误请求

    从 Salesforce 中使用 Google OAuth 时 我收到 400 错误请求 以下错误与无效的 grant type 有关 但如果您查看 使用刷新令牌 下的文档 您会发现它是正确的 https developers google
  • 为什么使用HTTP协议时需要指定端口号?

    即使我们使用HTTP协议 为什么还需要用IP地址指定端口号 例如 http xyz 8080 这到底是什么意思 我们已经知道 在使用 HTTP 时 请求将在端口 80 上提供服务 那么为什么我们要显式指定端口呢 HTTP 的默认端口为 80
  • 除了 GET 和 POST 之外,如何从浏览器向 RESTful 应用程序发送任何内容?

    我没有得到 RESTful 的东西 是的 我知道如何从浏览器向我的应用程序发送 GET 请求 这是通过 URL 链接 a href user someone 并且还可以通过form方法发送POST请求 a

随机推荐

  • 2023/5/9总结

    项目 xff1a 这俩天在看文件分流 xff0c 虽然看的原理是把文件切割 xff0c 传输的时候带着下标值 xff0c 或者在字节头去实现 xff0c 然后在服务器当中结合 但是实现起来遇到了很多问题 xff1a 1 需要另外开辟端口号来
  • putty使用方法,中文教程

    转自 http hi baidu com dba chen blog item ce6a7f54cb6522173b29351e html putty使用方法 xff0c 中文教程 序言 大致内容罗列如下 xff1a 最简单的使用 xff0
  • 用 VNC + Putty 把图形界面带出防火墙

    用 VNC 43 Putty 把图形界面带出防火墙 转自http blog sina com cn s blog 53a2aec8010009b6 html 2007 05 24 18 15 24 转载 分类 xff1a 工作 单位的服务器
  • 配置VNC+PuTTY+SSH Tunnel访问Linux

    转自 http blog 163 com yunlei ma blog static 12720893520098492716722 配置VNC 43 PuTTY 43 SSH Tunnel访问Linux 2009 09 04 21 27
  • 如何在c/c++里输出系统时间

    include lt stdio h gt include lt time h gt void main time t rawtime struct tm timeinfo time amp rawtime timeinfo 61 loca
  • 控制台窗口操作

    用于控制台窗口操作的API函数如下 xff1a GetConsoleScreenBufferInfo 获取控制台窗口信息 GetConsoleTitle 获取控制台窗口标题 ScrollConsoleScreenBuffer 在缓冲区中移动
  • 图像增强?图像复原??

    图像增强的目标是改进图片的质量 xff0c 例如增加对比度 xff0c 去掉模糊和噪声 xff0c 修正几何畸变等 xff1b 图像复原是在假定已知模糊或噪声的模型时 xff0c 试图估计原图像的一种技术 图像增强按所用方法可分成频率域法和
  • SQL SERVER DATETIME 常用日期格式转换

    我们经常出于某种目的需要使用各种各样的日期格式 xff0c 当然我们可以使用字符串操作来构造各种日期格式 但是有现成的函数为什么不用呢 xff1f SQL Server中文版的默认的日期字段datetime格式是yyyy mm dd Thh
  • hadoop学习之自定义对象实现 writeable

    Hadoop虽然 已经实现了一些非常有用的Writable xff0c 如Text IntWritable NullWritable等 xff0c 但有时候需要构造一些更加复杂的结果存入context中 xff0c 使用这些方法可能就不是那
  • C语言宏的用法详解

    1 简介 宏在C语言中是一段有名称的代码片段 无论何时使用到这个宏的时候 xff0c 宏的内容都会被这段代码替换掉 主要有两种宏 xff0c 他们的区别主要是在使用上面 xff0c 一种是在使用时类似于数据对象称为Object like x
  • Linux--day04\05

    知识点和问题 1 Linux组基本介绍2 查看文件的所有者3 创建一个组police 再创建一个用户tom xff0c 将tom放在police中 xff0c 然后使用tom来创建ok txt文件 xff0c 看看情况如何 4 使用root
  • 如何在Ubuntu上运行.run文件

    在Ubuntu上运行 run文件 xff0c 有以下几个步骤 xff1a 1 打开一个终端 ctrl 43 alt 43 t 2 cd 到 run文件所在目录 3 输入 34 chmod 43 x foo run 34 4 输入 34 fo
  • /dev/tty、/dev/ttyS/、/dev/ttyUSB区别

    1 dev tty 当前控制终端Terminal 可以使用命令 ps ax 来查看进程与哪个控制终端相连 xff0c 使用命令 tty 可以查看它 具体对应哪个实际终端设备 2 dev ttyn和 dev console xff08 虚拟
  • 怎么解决你的Segmentation fault (core dumped)问题

    http westsoftware blog 163 com blog static 260941092011460252776 开发一个Linux Unix C C 43 43 程序的时候 xff0c 有时候会出现莫名的core dump
  • 前端生成图表

    http www cnblogs com skiler p 6679828 html 1 常用的前端生成图表的工具HighCharts和echarts 2 具体内容可参考官方文档 xff0c 有一些具体实例 xff0c JS和HTML的代码
  • C语言与C++的区别终于有人说清楚了!

    点击蓝字 关注我们 来源于网络 xff0c 侵删 1 前言 在很大程度上 xff0c C 43 43 是C的超集 xff0c 这意味着一个有效的C程序也是一个有效的C 43 43 程序 C和C 43 43 的主要区别是 xff0c C 43
  • python3,浅谈with的神奇魔法

    在实际的编码过程中 xff0c 有时有一些任务 xff0c 需要事先做一些设置 xff0c 事后做一些清理 xff0c 这时就需要python with出场了 xff0c with能够对这样的需求进行一个比较优雅的处理 xff0c 最常用的
  • archlinux安装配置vnc+openbox

    为什么用openbox xff0c 因为它很小 xff0c 占用资源少 够我用了 我用linux大部分只用命令行界面就够了 图形界面程序用的最多的也就是浏览器了 安装相关软件包 span class token comment 更新下系统
  • 安装vsftpd,并将用户锁定到家目录中,不能切换其他目录

    安装vsftpd span class token function rpm span ivh vsftpd 3 0 2 28 el7 x86 64 rpm 创建用户 span class token function useradd sp
  • c语言——http编程

    HTTP协议简介 超文本传输协议是一种用于分布式 协作式和超媒体信息系统的应用层协议 HTTP是一个客户端终端 xff08 用户 xff09 和服务器端 xff08 网站 xff09 请求和应答的标准 xff08 一般基于TCP xff09