一、应用层的作用:
应用层是体系中最高的一层,直接为用户的应用进程(正在运行的程序)提供服务。
二、应用层的相关协议:
应用层的许多协议是基于客户服务器方式的。客户是服务请求方,服务器是服务提供方。
1.域名系统DNS:一整套从域名映射到IP的系统。
最初,通过互联网信息中心来管理hosts文件,使用hosts文件与IP地址的关系。
-如果一个新的计算机要接入网络,或者某个计算机IP变更,都需要到信息中心申请变更hosts文件。
-其他计算机也需要定期下载更新版本的hosts文件才能正确上网。
那么DNS系统解决了此问题。
–一个组织的系统管理机构,维护系统内的每个主机的Ip和主机名的对应关系。
–如果新计算机接入网络,将这个信息注册到数据库中。
–用户输入域名的时候,会自动查询DNS服务器,由DNS服务器检索数据库,得到对应的ip地址。因特网的域名结构:
DNS规定,域名中的标号都由英文字母和数字组成,每一个标号不超过63个字符,也不区分大小写字母。
一级域名:一般为企业域名,行政区域名,如ac(科研机构),com(工,商金融等企业),edu(教育机构),gov(国家的政府机构),mil(中国的国防机构),net(提供互联网服务的机构),org(非营利的组织)。
二级域名:公司名,学校名等。
三级域名:mail。- 域名服务器:
DNS服务器的管辖范围不是以域为单位,而是以“区”为单位,区是DNS服务器实际管辖范围。区可能小于等于域,但一定不可能大于域。
每一层的域名上都有自己的域名服务器,最顶层的是域名服务器。
每一级域名服务器都知道下层域名服务器的ip地址.(如不知道,则需向上层请求查询,最多回溯到根域名服务器请求查询,根域名服务器查询的结果返回给该层域名服务器)
每一级至少设置两个及以上的域名服务器。 - 域名的解析过程
-1.递归查询:
-2.迭代查询:
2.超文本传送协议HTTP
HTTP的特点
HTTP是面向事务的应用层协议,它是万维网上能够可靠的交换文件的重要基础。其端口号为80。HTTP使用了面向连接的TCP作为运输层协议,保证了数据的可靠传输。HTTP不必考虑数据在传输过程中被丢弃后又怎样被重传。
- HTTP协议本身是无连接的,即是说,虽然HTTP使用了TCP连接,但通信的双方在交换HTTP报文之前不需要建立HTTP连接。
- HTTP协议是无状态的。即是说同一个客户第二次访问同一个服务器上的页面时,服务器的响应与上一次被访问的相同(假定现在的服务器还没有把该页面更新),因为服务器不记得曾经访问过的客户。该种状态的特性简化了服务器的设计,使服务器更容易支持大量并发的HTTP请求。
HTTP的请求报文与响应报文:
下面来看看HTTP的请求报文:
下面使用telnet远程登陆www.baidu.com举例
HTTP请求报文格式:
HTTP请求报文主要由请求行、请求头部、请求正文3部分组成
1.请求行
由3部分组成,分别为:请求方法、URL(见备注1)以及协议版本,之间由空格分隔,
请求方法包括GET、HEAD、PUT、POST、TRACE、OPTIONS、DELETE以及扩展方法,当然并不是所有的服务器都实现了所有的方法,部分方法即便支持,处于安全性的考虑也是不可用的
协议版本的格式为:HTTP/主版本号.次版本号,常用的有HTTP/1.0和HTTP/1.1
2.请求头部
请求头部为请求报文添加了一些附加信息,由“名/值”对组成,每行一对,名和值之间使用冒号分隔
3,请求正文
可选部分,比如GET请求就没有请求正文
GET请求示例:
POST请求示例:
HTTP响应报文格式:
HTTP响应报文主要由状态行、响应头部、响应正文3部分组成
响应示例:
1.状态行
由3部分组成,分别为:协议版本,状态码,状态码描述,之间由空格分隔
状态代码为3位数字,200~299的状态码表示成功,300~399的状态码指资源重定向,400~499的状态码指客户端请求出错,500~599的状态码指服务端出错(HTTP/1.1向协议中引入了信息性状态码,范围为100~199)
这里列举几个常见的:
2.响应头部
与请求头部类似,为响应报文添加了一些附加信息
常见响应头部如下:
下面为自己实现的一个HTTP服务器。
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<string.h>
#include<arpa/inet.h>
#include<stdlib.h>
//./tcp_server 127.0.0.1 8080
void service(int sock,char*ip,int port)
{
char buf[1024];//用一个大的缓冲区来放客户端的数据
while(1){
buf[0]=0;
ssize_t s=read(sock,buf,sizeof(buf)-1);
if(s>0){
buf[s]=0;
printf("[%s:%d] say#%s\n",ip,port,buf);
char bbuf[1024];//写入到该缓冲区中
const char*hello="<h1>hello world</h1>";
sprintf(bbuf,"http/1.0 200 ok\ncontent-length:%lu\n\n%s",strlen(hello),hello);//将字符串写成%s的形式存在bbuf内
write(sock,bbuf,strlen(buf));//将其写入sock
}
else if(s==0){//write fd closed
printf("client [%s:%d]quit!\n",ip,port);
break;
}else{
printf("read error\n");
break;
}
}
}
int main(int argc,char*argv[])
{
if(argc!=3){
printf("Usage:%s [ip] [port]\n",argv[0]);
return 1;
}
int sock=socket(AF_INET,SOCK_STREAM,0);
if(sock<0){
perror("socket");
return 2;
}
struct sockaddr_in local;
local.sin_family=AF_INET;
local.sin_addr.s_addr=inet_addr(argv[1]);
local.sin_port=htons(atoi(argv[2]));
if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){
printf("bind error\n");
return 3;
}
if(listen(sock,5)<0){//listen sock
perror("listen");
return 4;
}
struct sockaddr_in peer;
while(1){
socklen_t len=sizeof(peer);
int client_sock=accept(sock,(struct sockaddr*)&peer,&len);
if(client_sock<0){
printf("accept error\n");
continue;
}
//sucess
printf("get a new connect,[%s:%d]\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
service(client_sock,inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));
close(client_sock);
}
return 0;
}
下面为显示的结果: