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 标头中发送 UTF-8 值会导致 Mojibake

    我想使用 servlet 发送阿拉伯语数据HTTPServletResponse给客户 我正在尝试这个 response setCharacterEncoding UTF 8 response setHeader Info arabicWo
  • 扩展(十进制,例如 400.1、401.4 等)HTTP 状态代码从何而来?

    我越来越多地看到十进制样式 HTTP 状态代码的激增 而且我似乎找不到任何 RFC 或其他 IETF 建议 甚至 W3C 草案或除 Microsoft IIS 文档之外的其他内容 请参阅https support microsoft com
  • 流星图像、CSS、“普通”Web 服务

    我经常看到这个问题出现 如何在我的 Meteor 网站上放置图像 如何使用 Meteor 托管 标准 网页内容 我尝试添加一个 img src img myimage png 标签但没有图像显示 如何在 Meteor 站点上托管一些文件 将
  • 同源政策目的可疑

    正如我所读到的 同源策略是防止源自 邪恶 域 A 的脚本向 良好 域 B 发出请求 换句话说 跨站点请求伪造 玩了一下我了解到的Access Control Allow Origin标头和CORS据我了解 它允许从好域 B 指定服务器 域
  • 如何使用 Java 以正确的编码检索 HTML 页面?

    如何使用页面编码中的 HTML 页面读取 HTTP 流 这是我用来获取 HTTP 流的代码片段 输入流读取器有编码可选参数 但我不知道如何获取它 URLConnection conn url openConnection InputStre
  • 是否可以使用 http url 作为 DirectShow .Net 中源过滤器的源位置?

    我正在使用 DirectShow Net 库创建一个过滤器图 该过滤器图通过使用 http 地址和 WM Asf Writer 来流式传输视频 然后 在网页上 我可以使用对象元素在 Windows Media Player 对象中呈现视频源
  • 使用 Java 通过 HTTP 下载未知长度的文件

    我想用java下载一个HTTP查询 但是我下载的文件在下载时有一个未确定的长度 我认为这将是相当标准的 所以我搜索并找到了它的代码片段 http snipplr com view 33805 http snipplr com view 33
  • 哪些具体用例需要通过 WebSockets 和长轮询使用 BOSH? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 防止表单重新提交

    第一页包含一个 HTML 表单 第二页 处理提交的数据的代码 第一页中的表格已提交 浏览器被重定向到第二页 第二页处理提交的数据 此时 如果刷新第二页 则会弹出 确认表单重新提交 警报 这可以预防吗 人们过去常采取两种方法 方法一 使用 A
  • Crystal lang如何从http获取二进制文件

    In Ruby require open uri download open http example com download pdf IO copy stream download my file pdf 如何在水晶中做同样的事情 我们
  • RESt api:根据身份验证对资源和内容进行识别

    我正在设计一个遵循 HATEOAS REST 原则的 API 但我不确定这个基本点 资源识别 假设这个网址 images它公开了用户 向该用户 上传的所有图像 假设我使用 oauth 访问令牌进行身份验证 images 的内容将根据授权标头
  • Response.Redirect 并不总是重定向

    我们在一个工作不一致的页面上有一个简单的 Response Redirect IIS 6 0 大多数情况下 它会正确重定向 但我们收到一些用户抱怨 他们没有重定向 而是看到 302 对象移至此处 页面 该页面显示标题信息以及正确的位置 如果
  • 如何解决 302 重定向上的 POST 更改为 GET 的问题?

    我网站的某些部分只能通过 HTTPS 访问 不是整个网站 安全与性能妥协 并且如果通过纯 HTTP 发送请求 则 HTTPS 是通过对安全部分的请求进行 302 重定向来强制执行的 问题是对于所有主流浏览器来说 如果您在 POST 上执行
  • 如何让 HttpClient 返回状态码和响应正文?

    我试图让 Apache HttpClient 触发 HTTP 请求 然后显示 HTTP 响应代码 200 404 500 等 以及 HTTP 响应正文 文本字符串 重要的是要注意我正在使用v4 2 2因为大多数 HttpClient 示例都
  • Chrome 问题 - 视频流和会话冲突

    我在使用 javascript 和 PHP 实现视频时遇到问题 索引 php session start do other stuff include video php 视频 php
  • Node.js 上的 Connect 出现“无法 GET /”

    我正在尝试使用以下方式开始提供一些静态网页connect像这样 var connect require connect var nowjs require now var io require socket io var app conne
  • 在防火墙后面使用 GitHub,无需 SSH 访问

    我真的很想使用 GitHub 但我的公司一切都被锁定了 现在 我只能通过HTTP协议使用Tortoise SVN 我可以以同样的方式使用 GitHub 吗 如果是这样 怎么办 我认为你一直能够克隆github https github co
  • 使用 HTTP-Basic 身份验证发出 HTTP GET 请求

    我需要为我正在开发的 Flash Player 项目构建一个代理 我只需要使用 HTTP Basic 身份验证向另一个 URL 发出 HTTP GET 请求 并提供来自 PHP 的响应 就好像 PHP 文件是原始源一样 我怎样才能做到这一点
  • 如何在GO中执行HEAD请求?

    我想使用 GO net http 获取页面的内容长度 我可以在终端中使用curl i X HEAD https golang org然后检查内容长度字段 use http Head https golang org pkg net http
  • Unicorn + Rails + 大型上传

    我试图在使用 Rails 在 Heroku 上运行 Unicorn 时允许进行大型上传 但我意识到任何大型上传可能需要比 Unicorn 工作线程的超时时间更长的时间 这意味着 我见过这种情况发生 Unicorn 主进程将杀死上传大文件的工

随机推荐

  • Gazebo中sdf文件和urdf和xacro文件的区别

    sdf文件 urdf文件和xacro文件都是模型文件 xacro文件是urdf文件的改进版 xff0c urdf文件只能在rviz等中显示 xff0c 不能在仿真器中显示出来 xacro文件可以在gazebo仿真器中显示出来 xff0c 相
  • Gazebo的xacro文件添加各种plugins

    官网地址 xff1a http gazebosim org tutorials tut 61 ros gzplugins Tutorial Using Gazebo plugins with ROS Gazebo plugins give
  • ROS中spawn_model方式加载xacro文件,设置模型的位置(xyz,rpy)

    例如加载turtlebot机器人launch文件如下 xff1a 在gazebo仿真中最后都是通过这种方式加载xacro文件的 lt launch gt lt arg name 61 34 base 34 gt lt arg name 61
  • BT1120

    BT1120是高清晰度电视 HDTV 演播室信号数字接口 图像数据是怎么用二进制数据组织在一起的呢 xff1f 个人理解 xff1a 在BT1120标准中说明的图像数据指的是图像的有效尺寸的数据 因为我们看到编码信号包括图像数据和图像基准码
  • 2021-10-22 常用的串口通讯协议

    串口通讯是什么 学术解释是 xff0c 通过总线在一个时间点连续发送一位数据的方法 如同弓箭手频繁射出弓箭一般 xff0c 嗖 嗖 嗖 串口通讯协议是什么 说的大白话一点 xff0c 就是串口通信时所使用的协议传输方式 串口通讯协议有几种呢
  • curl 命令详解

    curl 是一种命令行工具 xff0c 作用是发出网络请求 xff0c 然后获取数据 xff0c 显示在 34 标准输出 34 xff08 stdout xff09 上面 它支持多种协议 xff0c 下面列举其常用功能 一 查看网页源码 直
  • RS485/云台控制(PTZ)学习文档

    RS485 云台控制 xff08 PTZ xff09 学习文档 zxf 一 项目任务 xff1a 在linux环境下通过RS485串口实现对云台镜头的各种控制 xff08 包括摄像头的打开 xff0c 关闭 xff0c 各个方向的运动及运动
  • 为何某些公司不允许使用C++STL

    点击蓝字 关注我们 最初开始禁用 C 43 43 STL xff0c 是因为早期项目编码实践中留下的惯例 xff0c 被后来的程序员继承下来 老项目中这种选择尤其地多 不过如果有人将其上升到公司行为在不同项目中全面禁用 STL xff0c
  • C++vector用法总结

    点击蓝字 关注我们 来源自网络 xff0c 侵删 一 vector 1 vector 说明 1 xff09 vector是C 43 43 标准模板库中的部分内容 xff0c 它是一个多功能的 xff0c 能够操作多种数据结构和算法的模板类和
  • halcon中的Pose

    Pose 姿态描述的是一个刚性的3D转换 xff0c 即 xff0c 一种由任意平移和旋转组成的变换 在Halcon中 xff0c 一个pose是具有7个参数的元组 xff1a 3个参数描述平移 xff08 TransX TransY Tr
  • halcon中阈值分割算子用法

    1 threshold Image Region MinGray MaxGray xff1a 通过给定的阈值区间对图像进行分割 效果图 xff1a read image Audi2 39 audi2 39 fill interlace Au
  • HALCON guided_filter导向滤波算子分析

    1 guided filter Image ImageGuide ImageGuided Radius Amplitude 可应用在图像增强 xff0c HDR压缩 图像抠图及图像去雾等场景 参数 xff1a Radius xff1a 滤光
  • halcon edges_image算子分析

    edges image Image ImaAmp ImaDir Filter Alpha NMS Low High xff1a 使用Deriche Lanser Shen或者Canny 滤波器进行边缘提取 参数 xff1a Image xf
  • C# NModbus的主从站开发以及Modbus Slave、Modbus Poll工具的使用

    NModbus的主站开发 1 开发环境要求 xff1a PC端作为主站 xff0c 控制器作为从站 2 PC端初始化代码 xff1a serialPort 61 new SerialPort serialPort PortName 61 3
  • OpenCVSharp Mat.Set<T>修改像素颜色

    笔记 xff1a Mat Set lt T gt 方法修改图像中的颜色 xff0c T的类型不能是Scalar 应为Vec3b xff0c 否则颜色修改失败 C 代码 xff1a Mat labs 61 new Mat int counts
  • VSCode idea 配置xml文件的dtd约束文件

    如上图配置XML文件的智能提示功能通过dtd文件 xff1a 1 通过VSCode 的扩展功能下载XML插件 xff08 注意 xff1a 插件内是包含dtd文件配置功能 xff09 配置方式 xff1a 1 DOCTYPE xff1a l
  • 关于0xAA和0x55

    许多串口通讯中测试或握手信号使用AA或55这两个特殊的十六进制数 xff0c 在许多PIC内部的 EEPROM 改写也使用这两个数作为敲门砖 xff0c 初学者可能不解何为 xff0c 其实如果将这两个数展开成二进制就可明白为什么 xff1
  • APS .Net MVC 之APIController与Controller的区别

    APIControllerController开发模式WebAPIMVC命名空间System Web HttpSystem Web Mvc返回方式json text或者xml texthtml textaction的默认请求方式postpo
  • DBeaver连接informix数据库乱码

    在工具栏选择数据库 驱动管理 informix编辑 xff0c 示例URL中添加NEWCODESET 61 utf8 8859 1 819 CLIENT LOCALE 61 en US utf8 DB LOCALE 61 en US 885
  • c语言——http编程

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