您的位置:首页 > 理论基础 > 计算机网络

http协议 telnet linux c http client 通讯

2015-08-11 17:34 696 查看

http协议简介

用firefox的firebug(F12)调试看看http的请求与响应



GET / HTTP/1.1
GET表示一个读取请求,将从服务器获得网页数据,/表示URL的路径,URL总是以/开头,/就表示首页,最后的HTTP/1.1指示采用的HTTP协议版本是1.1。目前HTTP协议的版本就是1.1,但是大部分服务器也支持1.0版本,主要区别在于1.1版本允许多个HTTP请求复用一个TCP连接,以加快传输速度。
Host: www.baidu.com
请求报头域主要用于指定被请求资源的Internet主机和端口号,它通常从HTTP URL中提取出来的.此处表示请求的域名是www.baidu.com,且使用缺省端口号80,若指定了端口号,则变成:Host:http://baidu.com/:指定端口号
User-Agent:浏览器类型,如果Servlet返回的内容与浏览器类型有关则该值非常有用
Accept: 请求报头域用于指定客户端接受哪些类型的信息。eg:Accept:image/gif,表明客户端希望接受GIF图象格式的资源;Accept:text/html,表明客户端希望接受html文本.
Accept-Charset:请求报头域用于指定客户端接受的字符集。eg:Accept-Charset:iso-8859-1,gb2312.如果在请求消息中没有设置这个域,缺省是任何字符集都可以接受。
Accept-Language:浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到.如果请求消息中没有设置这个报头域,服务器假定客户端对各种语言都可以接受。
Accept-Encoding: 浏览器能够进行解码的数据编码方式,比如gzip。如果请求消息中没有设置这个域服务器假定客户端对各种内容编码都可以接受.Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间.
Cookie:这是最重要的请求头信息之一
Cache-Control:用于指定缓存指令,缓存指令是单向的(响应中出现的缓存指令在请求中未必会出现),且是独立的(一个消息的缓存指令不会影响另一个消息处理的缓存机制),HTTP1.0使用的类似的报头域为Pragma。请求时的缓存指令包括:no-cache(用于指示请求或响应消息不能缓存)、no-store、max-age、max-stale、min-fresh、only-if-cached;响应时的缓存指令包括:public、private、no-cache、no-store、no-transform、must-revalidate、proxy-revalidate、max-age、s-maxage.
Connection: 表示是否需要持久连接。如果Servlet看到这里的值为“Keep-Alive”,或者看到请求使用的是HTTP 1.1(HTTP 1.1默认进行持久连接),它就可以利用持久连接的优点,当页面包含多个元素时(例如Applet,图片),显著地减少下载所需要的时间。要实现这一点,Servlet需要在应答中发送一个Content-Length头,最简单的实现方法是:先把内容写入ByteArrayOutputStream,然后在正式写出内容之前计算它的大小
Authorization:请求报头域主要用于证明客户端有权查看某个资源。当浏览器访问一个页面时,如果收到服务器的响应代码为401(未授权),可以发送一个包含Authorization请求报头域的请求,要求服务器对其进行验证。




HTTP响应分为Header和Body两部分(Body是可选项,它是HTML源码)
200表示一个成功的响应,后面的OK是说明。失败的响应有404 Not Found:网页不存在,500 Internal Server Error:服务器内部出错,等等
Date:当前的GMT时间,可以用setDateHeader来设置这个头以避免转换时间格式的麻烦
Content-Type指示响应的内容,这里是text/html表示HTML网页。请注意,浏览器就是依靠Content-Type来判断响应的内容是网页还是图片,是视频还是音乐。浏览器并不靠URL来判断响应的内容,所以,即使URL是http://example.com/abc.jpg,它也不一定就是图片
Content-Length:实体报头域用于指明实体正文的长度,以字节方式存储的十进制数字来表示。
Content-Encoding:文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面


HTTP格式

每个HTTP请求和响应都遵循相同的格式,一个HTTP包含Header和Body两部分,其中Body是可选的。

HTTP协议是一种文本协议,所以,它的格式也非常简单。HTTP GET请求的格式:

GET /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3


每个Header一行一个,换行符是\r\n。

HTTP POST请求的格式:

POST /path HTTP/1.1
Header1: Value1
Header2: Value2
Header3: Value3

body data goes here...


当遇到连续两个\r\n时,Header部分结束,后面的数据全部是Body。

HTTP响应的格式:

200 OK
Header1: Value1
Header2: Value2
Header3: Value3

body data goes here...


HTTP响应如果包含body,也是通过\r\n\r\n来分隔的。请再次注意,Body的数据类型由Content-Type头来确定,如果是网页,Body就是文本,如果是图片,Body就是图片的二进制数据。

当存在Content-Encoding时,Body数据是被压缩的,最常见的压缩方式是gzip,所以,看到Content-Encoding: gzip时,需要将Body数据先解压缩,才能得到真正的数据。压缩的目的在于减少Body的大小,加快网络传输。

要详细了解HTTP协议,推荐“HTTP: The Definitive Guide”一书,非常不错,有中文译本:HTTP权威指南

用telnet模拟http请求

telnet www.baidu.com 80 //enter
GET / HTTP/1.1      //enter
HOST:           //enter




——baidu服务器就会返回:



*linux c http*

/*****************************************
> File Name : client_test.cpp
> Description : the test http client
> Author : linden
> Date : 2015-08-12
*******************************************/

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <time.h>
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>

// 用C代码模拟浏览器IE(http client)访问web(http server)的行为

int main()
{

char szWeb[] = "www.baidu.com";
hostent *pHost = gethostbyname(szWeb);

// 度娘的ip地址
const char* pIPAddr = inet_ntoa(*((struct in_addr *)pHost->h_addr));
printf("web server ip is : %s\n", pIPAddr);

struct sockaddr_in  webServerAddr;
webServerAddr.sin_family = AF_INET;
webServerAddr.sin_addr.s_addr = inet_addr(pIPAddr);
webServerAddr.sin_port = htons(80);

// 创建客户端通信socket
int sockClient = socket(AF_INET, SOCK_STREAM, 0);

int nRet = connect(sockClient, (struct sockaddr*)&webServerAddr, sizeof(webServerAddr));
if (nRet < 0)
{
printf("connect error\n");
return 1;
}

// 准备向度娘发送http的GET请求
char szHttpRest[1024] = { 0 };
sprintf(szHttpRest, "GET /index.html HTTP/1.1\r\nHost:%s\r\nConnection: Keep-Alive\r\n\r\n", szWeb);
//sprintf(szHttpRest, "GET / HTTP/1.1\r\nHost:%s\r\n\r\n", szWeb);
printf("\n---------------------sendbuf is :---------------------\n");
printf("%s\n", szHttpRest);

// 利用tcp向度娘发送http的GET请求
nRet = send(sockClient, szHttpRest, strlen(szHttpRest) + 1, 0);
if (nRet < 0)
{
printf("send error\n");
return 1;
}

// 把度娘返回的信息保存在文件test.txt中
FILE *fp = fopen("test.txt", "w");
while (1)
{
char szRecvBuf[2049] = { 0 };
nRet = recv(sockClient, szRecvBuf, 2048, 0);
printf("szRecvBuf = %s\n", szRecvBuf);
// 接收错误
if (nRet < 0)
{
printf("recv error\n");
goto LABEL;
}

// 度娘主动断开了连接
if (0 == nRet)
{
printf("connection has beed closed by web server\n");
goto LABEL;
}

static int flag = 0;
if (0 == flag)
{
printf("writing data to file\n");
flag = 1;
}

// 把度娘返回的信息写入文件
fputc(szRecvBuf[0], fp);
}

LABEL: // 这个单词不要写错啦, 很多童鞋容易写错
fclose(fp);
close(sockClient);

return nRet < 0 ? 1 : 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: