HTTP(HyperText Transfer Protocol)超文本传输协议,用于解决万维网(www)Server/Client间统一通信的问题,面向事务(transaction-oriented,一系列信息的完整传输交换)应用层协议
URI(Uniform Resource Identifier), 区别不同网络事物的抽象概念,如sina代表新浪网,qq号代表一个账户
URL(Uniform Resource Locator),统一资源定位符 = “协议://IP地址:端口/路径和文件名”,访问机制+网络位置,(大小写不敏感)
URN(Uniform Resource Name),来唯一标识一个实体,特定命名空间+名字,不需要知道地址或访问机制
网页访问过程
PS:为加快响应用户的速度,音视频是点击页面上的播放按钮后再次建立连接并传输
从Client请求到得到文档计时:RTT*2+文档传输时间
HTTP特性
Proxy Server,又被称为“万维网高速缓存(Web cache)”,将请求和响应暂存于本地磁盘中,新请求与暂存请求相同时直接返回暂存响应,举例
Client优先访问Proxy Server,Proxy Server未缓存响应时,由Proxy Server 向 Origin Server 发起TCP链接及HTTP请求,收到请求对象后,先复制缓存在本地存储器中再通过请求时建立的TCP连接返回对象
分为请求报文和响应报文,ASCII编码的字段组成
开始行
CR(Carriage Return)回车 ’ r ’ 与 LF(Line Feed)换行 ‘n’ 结尾。 换行与回车的历史起源
请求报文中: 请求行 (Request-Line)
GET IP:8080/home/mypage.html HTTP/1.1
方法(method)有:GET,PUT,OPTION,DELETE,TRACE,CONNECT,POST
响应报文中: 状态行 (Status-Line)
HTTP/1.1 202 Accepted
HTTP/1.1 404 Not Found
状态码(Status-Code)有:
1xx:通知信息
2xx:成功
3xx:重定向
4xx:请求错误(不能完成)
5xx:服务器差错无法完成请求
首部行
实体主体(entity body)
举例:
GET /home/mypage.html HTTP/1.1rn {URL使用相对路径}
Host: 域名rn {首部给出域名}
Connection: Closern {传输结束请求文档即可释放连接}
Accept-Language: cnrn
HTTP/1.1 301 Moved Permanently {永久转移}
Location: IP:port/location/mypage.html {新的URL}
Server与Client间传递的状态信息
HyperText Markup Language 超文本标记语言
<html><head><title>好诗</title></head><body> <H1>一级标题</H1><H2>春江花月夜</H2><p>春江潮水连海平,海上明月共潮生。<br>滟滟随波千万里,何处春江无月明! <br>江流宛转绕芳甸,月照花林皆似霰; <br>空里流霜不觉飞,汀上白沙看不见。 <br>江天一色无纤尘,皎皎空中孤月轮。 <br>江畔何人初见月?江月何年初照人? <br>人生代代无穷已,江月年年望相似。</P><p>My UNIX do not have Chiness charactor set</P></body>
</html>
使用ASCII编码,浏览器直接打开查看效果
HTML允许在网页中插入图像(内含图像inline image),其中gif格式压缩后体积最小
远程连接:终点在其他网站
本地连接:终点在本计算机
静态文档(static document)
工人写完后不再改变,简单但不灵活
动态文档(dynamic document)
浏览器访问Server时程序动态创建
通用网关接口(CGI,Common Gateway Interface
是一种定义动态文档的创建,数据输入(给Server应用程序) 和 输出的标准
CGI程序 是 脚本程序(script language)
活动文档(active document)
了解Socket套接字编程,主要
变量有:
sockaddr
socket(_fd)
函数有:
Client端的socket()、send()、recv()
Server端Listen()、accept()
#include <iostream>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>
//-------------------
//V1.0 接收请求,显示报文
//-------------------
using namespace std;
int main(void)
{int listener=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(listener==(int)(~0)){ cout<<"Listenner Initiate Failure!"<<endl;return 0;}struct sockaddr_in ServerAddr;ServerAddr.sin_family=AF_INET;ServerAddr.sin_port=htons(8080); //http服务端口ServerAddr.sin_addr.s_addr=INADDR_ANY;if(bind(listener,(struct sockaddr*)&ServerAddr,sizeof(ServerAddr))== -1){cout<<"Binding Failure!"<<endl;return 0;}if(listen(listener,5)==-1){cout<<"Listening Start Failure!"<<endl;return 0;}int Client_id;struct sockaddr_in ClientAddr;socklen_t ClientAddrLen = sizeof(ClientAddr);while(1){cout<<"<<endl;Client_id=accept(listener,(struct sockaddr*)&ClientAddr,&ClientAddrLen);if(Client_id==(int)(~0)){cout<<"Accept Error!"<<endl;continue;}cout<<"Accept message from Client :"<<endl;char recvData[512]={};recv(Client_id,recvData,512,0);cout<<recvData<<endl;const char* cmd=recvData;close(Client_id);if(!strcmp(cmd,"CloseServer"))break;}close(listener);return 0;
}
在Unix系统下运行以上源文件编写的HTTPServer,再使用其他主机上的浏览器通过URL访问任意Server上的资源,HTTPServer都会打印HTTP请求的内容
可以手写响应报文:
char sendData[512]={0};
strcpy(sendData,"HTTP/1.1 202 OK!rncontent-type: text/html; charset=UTF-8rnrn<html><head><title>Try</title></head><body><H1>Title-C1</H1></body></html>");
send(Client_id,&sendData,512,0);
再使用其他主机上的浏览器通过URL访问任意Server上的资源,HTTPServer将返回响应报文
在浏览器中可以看到响应报文实体(html文档)在浏览器中显示的效果
按下F12使用控制台,刷新后重新访问URL,可查看响应报文的标头
首先提取请求中的文件名,然后使用中的ifstream类open(请求的file),open()函数搜索可执行文件所在的目录下是否存在目标文件,成功打开后读取内容,并与HTTP的开始行、首部行,一并返回
//-----------------------------------
//V2.0 接受请求,分析URL,响应传输html文档
//-----------------------------------
#include <iostream>
#include <string.h>
#include <string>
#include <fstream>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>using namespace std;
int main(void)
{int listener=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);if(listener==(int)(~0)){ cout<<"Listenner Initiate Failure!"<<endl;return 0;}struct sockaddr_in ServerAddr;ServerAddr.sin_family=AF_INET;ServerAddr.sin_port=htons(8080);ServerAddr.sin_addr.s_addr=INADDR_ANY;setsockopt(listener, SOL_SOCKET, SO_REUSEPORT, (char*)&ServerAddr, sizeof(ServerAddr));if(bind(listener,(struct sockaddr*)&ServerAddr,sizeof(ServerAddr))== -1){cout<<"Binding Failure!"<<endl;return 0;}if(listen(listener,5)==-1){cout<<"Listening Start!"<<endl;return 0;}int Client_id;struct sockaddr_in ClientAddr;socklen_t ClientAddrLen = sizeof(ClientAddr);while(1){cout<<"<<endl;//--接收请求--Client_id=accept(listener,(struct sockaddr*)&ClientAddr,&ClientAddrLen);if(Client_id==(int)(~0)){cout<<"Accept Error!"<<endl;continue;}cout<<"Accept message from Client :"<<endl;char recvData[512]={0};recv(Client_id,recvData,512,0);recvData[511]='