/*
对HTTP协议进行分析:
测试环境:
WIN 2K -SP4
Apache/1.3.29 (Win32)
IE 6.0
Firefox/1.0
测试步骤:
1:先建立TCP连接。
2:发送如下请求:
GET /index.html HTTP/1.1
Accept:*?*
Accept-Language: zh-cn
User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)
Host:192.168.0.119
Connection: Keep-Alive
3:如后接受数据:
接受到的的结构如下: HTTP协议回应 + 网页正文 + HTTP的结尾结构
//------------------------------------------------------------------------具体数据如下
HTTP/1.1 200 OK
Date: Mon, 19 Dec 2005 10:51:54 GMT
Server: Apache/1.3.29 (Win32)
Last-Modified: Tue, 16 Mar 2004 12:24:28 GMT
ETag: "0-dab-4056f1fc"
Accept-Ranges: bytes
Content-Length: 3499
Keep-Alive: timeout=30, max=100
Connection: Keep-Alive
Content-Type: text/html
//**************************************网页正文(略)
HTTP/1.1 414 Request-URI Too Large
Date: Mon, 19 Dec 2005 10:51:54 GMT
Server: Apache/1.3.29 (Win32)
Connection: close
Content-Type: text/html; charset=iso-8859-1
Request-URI Too Large
The requested URL's length exceeds the capacity
limit for this server.
request failed: URI too long
--------------------------------------------------------------------------------
Apache/1.3.29 Server at localhost Port 8080
//------------------------------------------------------------------------数据结束
这之间还要有一个地方值得注意的就是当发出请求后,服务器回送数据时是分段发送的。
比如Apache/1.3.29 (Win32)返回一个大网页数据的时候就发送了5个包
1,2,3,4包是4098字节,最后剩下的数据由第5个包返回是1953个字节。
这5个包的数据结构如下:
1包:HTTP回应头结构 + 网页正文
2包:网页正文
3包:网页正文
4包:网页正文
5包:网页正文 + HTTP回应结尾结构
今天上午大哥说的东西其实就是这样一个东西:
1:SERVER开一个端口80。
2:CLIENT 连接 SERVER 用TCP协议,然后提出一个HTTP请求。
3:CLIENT 接收 SERVER 的数据,结构:HTTP回应头结构 + 文件内容 + HTTP回应结尾结构
从这些我们基本就可以看出来HTTP协议是建立在TCP协议之上。协议的请求和回应的结构也不是很严格。
这点和TCP,UDP等协议比较起来,HTTP协议并不像TCP/UDP等协议严格。
其实如果要较细致的学习这个协议,主要就是学习请求和回应的格式。
这是我截获的 IE6.0 的HTTP请求,访问命令:[url]http://192.168.0.119:800[/url]
GET / HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-powerpoint, application/vnd.ms-excel, application/msword, *?*
Accept-Language: zh-cn
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Host: 192.168.0.119:800
Connection: Keep-Alive
这是我截获的 firefox 的HTTP请求,访问命令:[url]http://192.168.0.119:800[/url]
GET / HTTP/1.1
Host: 192.168.0.119:800
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.0; zh-CN; rv:1.7.5) Gecko/20041224 Firefox/1.0
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*?*;q=0.5
Accept-Language: zh-cn,zh;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
注:以上请求里面有都一个*?*,其实这“?”应该是“/” 原因是因为是程序里面的注释符号
今天就着昨天的研究成果上面又具体的看了一下,还那昨天的那5个包做例子:
这之间还要有一个地方值得注意的就是当发出请求后,服务器回送数据时是分段发送的。
比如Apache/1.3.29 (Win32)返回一个大网页数据的时候就发送了5个包
1,2,3,4包是4098字节,最后剩下的数据由第5个包返回是1953个字节。
(info_php.php)
这5个包的数据结构如下:
1包4098:HTTP回应头结构 + 5个字节的数据() + 网页正文
2包4098:5个字节的数据() + 网页正文
3包4098:5个字节的数据() + 网页正文
4包4098:5个字节的数据() + 网页正文
5包1953:5个字节的数据() + 网页正文 + 5个字节的数据(通常是0) + HTTP回应结尾结构 + 网页结构
以上是对大于两个分段的网页的测试:(index.htm)
两个分段的网页:
1包4096:HTTP回应头结构 + 网页正文 + HTTP回应结尾结构 + 网页结构(一半)
2包195:网页结构(另一半)
以上是对大于一个分段的网页的测试:(index.html)
1包949: HTTP回应头结构 + 网页正文 + HTTP回应结尾结构 + 网页结构
一点小小的疑惑:当我测试普通的网页(*.html)反回分段时没有那5个字节的数据。
但当我测试动态网页(*.php)时在里面有那5个字节的数据,我不明白是不是里面还有什么别的机制来控制
HTTP协议的数据分段。另外说一点就是,那个5个字节的数据是16进制的数据。
大概是代表本分段里面的网页正文数据的字节数。
相信HTTP协议里面还有我没有发现的东西,但基本的东西我想我这里面写应该差不多了!
下面是我测试的小程序代码:
*/
//write by Gxter
//blog gxter.bokee.com
#include "stdio.h"
#include "winsock.h"
#include "conio.h"
#pragma comment(lib,"ws2_32")
int prot = 80;
int error=0;
char pagetext[40000]="/0"; //接受主机回应
char msg[0x30000]; //请求字符串
void httphead(); //填写HTTP协议--请求
int main()
{
int iret;
WSADATA wsa;
SOCKET sock;
struct sockaddr_in sin;
httphead();//写HTTP请求的函数
if(WSAStartup(MAKEWORD(2,2),&wsa))
{
printf("WSAStartup Error: %d/n",WSAGetLastError());
getche();
return -1;
}
if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))==INVALID_SOCKET)
{
printf("Socket Error: %d/n",WSAGetLastError());
getche();
return -1;
}
sin.sin_family=AF_INET;
sin.sin_port=htons(8080);
sin.sin_addr.s_addr=inet_addr("192.168.0.119");
if(connect(sock,(struct sockaddr *)&sin,sizeof(sin))==SOCKET_ERROR)
{
printf("Connect Error: %d/n",WSAGetLastError());
printf("请检测网络连接!/n");
getche();
return -1;
}
if((iret=send(sock,msg,sizeof(msg),0))==SOCKET_ERROR)
{
printf("Send Error: %d/n",WSAGetLastError());
getche();
return -1;
}
while(true)
{
memset(pagetext,0,sizeof(pagetext));
if((iret=recv(sock,pagetext,sizeof(pagetext),0))==SOCKET_ERROR)
{
printf("Recv Error: %d/n",WSAGetLastError());
getche();
return -1;
}
//-------------------------------------
printf("%d/n",iret);
printf("Re:/n");
/*
for(int i=0 ;i {
printf("%c-",pagetext[i]);
printf("%d-",pagetext[i]);
//if(i==9)
// printf("/n");
}
*/
printf("%s",pagetext);
printf("/n*************end*******************/n");
//-------------------------------------
if(pagetext[0] == 0)
{
break;
}
}
//----------------------------------------------
closesocket(sock);
WSACleanup();
getche();
return 0;
}
void httphead()
{
strcat(msg,"GET /php_info.php HTTP/1.1"); //----->GET /default.asp HTTP/1.1
strcat(msg,"/r/n");
strcat(msg,"Accept:*/*");
strcat(msg,"/r/n");
strcat(msg,"Accept-Language: zh-cn");
strcat(msg,"/r/n");
strcat(msg,"User-Agent: Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)");
strcat(msg,"/r/n");
strcat(msg,"Host:192.168.0.119"); //------->
strcat(msg,"/r/n");
strcat(msg,"Connection: Keep-Alive");
strcat(msg,"/r/n");
strcat(msg,"/r/n");
//printf("%s",msg);//显示发送的头部
//getchar();
}