应用层是tcp/ip五层模型的最高层,用于为用户提供服务。从应用层看通讯,应该是两个通信端点之间进程之间的逻辑连接。例如:A主机访问了B主机,对于二者而言,虽然通信过程中存在多个物理链路。但是对应用层而言,他仅仅关注A程序到B程序的连接。
需要注意的是:因为应用层作为最高层的协议集合,所以对应用层协议的添加和去除显得更容易,并不用考虑上层协议的耦合。
标准的应用层协议:
一些我们使用的协议如:http,已经有标准因特网管理,使用中需要严格按照规范。
非标准的应用层协议:
而实际上我们自己可以约定应用层通信之间的一些细节,自己编写非标准的应用层程序,如果仅仅是私人使用,这样的非标准也是可行的。
通讯模式:
客户-服务器(c/s)模式:
通信两端扮演不同角色,客户端需要向一台服务器发送请求,服务器应该一直运行,为客户端提供服务。
对等模式(p2p):
这种模式并不需要一台提供服务的服务器,通信两端是对等的,即可能提供服务,也可能接受服务。
混合模式:
把前两种有点混合的通信模式
客户-服务器模式(c/s):
API(application programming interface):
对计算机而言,总需要一些指令去告诉计算机该怎么做,例如,键盘和显示器,计算机通过键盘的输入读取所需信息,并且在显示器显示,这样的操作实际上发生在我们和应用程序和操作系统之间,操作系统提供了这些操作需要要的api,也就是说,如果有这样一套应用层协议的程序,那么也需要操作系统来解读这样的程序,实际上,操作系统封装了底层协议为应用层提供服务器,包括TCP/ip协议。这样的一套为应用层提供服务的接口即使API(application programming interface),三种这样的网络api分别是:socket(套接字) 接口,Transport Layer Interface,TLI(传输层接口)和Stream(流接口)。
对于socket觉得比较抽象,暂且把Socket理解为一种应用程序创建的抽象数据结构。
也就是说应用程序进程通过对socket访问,来请求和接受响应,其余的可以理解为操作系统以及内置的TCP/IP的工作。
socket地址:
有了接口,数据结构,还需要一个地址来区别两个通信端点之间的位置。
地址由一个32位IP地址和一个16位端口号组成,用:隔开
例如:210.38.136.66:8049
前面的ip是用来区别哪台主机,端口是用来区别那个进程,也就是是浏览器还是你的QQ。
本地Socket地址:
对服务器和客户一样的,都有操作系统提供一个ip地址,对于服务器,端口如果是标准进程,如http,那么就是80,已经事先分配好,对于客户端,发送请求的端口应该是一个临时的端口。
远程Socket地址:
对服务器程序而言,他并不知道稳定的远程通信地址,因为他每天为千千万万用户提供服务,对于客户端程序而言,他可能已经知道需要发送到那个服务器地址获取服务。
cs模式使用来自传输层的服务,比如无连接不可靠,但是速度佳的udp服务。也会使用,面向连接可靠的字节流传输协议tcp协议。也可以是结合两种的sctp协议。
客户-服务器模式的应用:
Web和http:
应该说,当今web两大特点,分布式,可链接。
这使得这样一个关系就像一个蜘蛛网。
浏览器:
这个是我们访问web的一个应用程序。
它包含三个部分,
控制程序:控制和用户以及其他部分的程序。
解释程序:最常见的是运行了js脚本的页面,必须有内置解释器来解释js语言,提供dom接口。
客户协议:浏览器包含了各种各样的协议。
web服务器:Apache,nginx.
URL(uniform Resource locator)统一资源定位符:
说的高大上。
其实本质就是用来说明四个东西:使用了什么协议,哪个主机,哪个端口,哪个页面。
所以就是这样:https://github.com/turingwu/
https :协议
github.com :host(通过dns解释后即使前面的sock地址:111.111.111.111:111)
turing:路径。
http1.1版本之前是非持续的连接,他和他之后是默认持续连接。
用tcp三次握手为例子
非持续连接:
这会发现,每个一个请求都需要重复三次握手进行连接。
可持续连接:
http是以报文方式传输的:
请求报文格式:
例子:
GET /usr/bin/image1 HTTP/1.1
Accept: image/gif
aaa
请求方法:
方法 动作 方法 动作
GET 获取文档 TRACE 回送输入请求
HEAD 请求文档的信息,而不是文档本身 DELETE 删除页面
PUT 从客户端向服务器发送文档 CONNECT 预留
POST 客户端向服务器发送信息 OPTIONS 询问可用选项
请求头部键:
头部 描述 头部 描述
User-agent 标示客户端程序 Host 客户端主机端口号
Accept-charset 给出客户端接受的字符 Date 当前日期
Accept-encoding 客户端可以处理的编码方案 Upgrade 首选协议
Accept-language 给出客户端处理的语言 Cookie 给你cookie
Authorization 客户端许可 If-Modified-Since 判断事非指定日期后被修改
响应报文:
响应头部键名称:
头部 描述 头部 描述
Date 当前日期 Content-Length 给出文档长度
Upgrade 首选的通信协议 Content-Type 指定媒体类型
Server 给出服务器信息 Location 指出新建或者移动后文档位置
Set-Cookie 服务器要求客户存层cookie Accept-Ranges 服务器会接受的请求字节范围
Content-Encoding 编码规范 Last-modified 给出上次改变的日期和时间
Content-Language 指定语言
例子:
HTTP/1.1 200 OK
Server: nginx/1.4.4
Date: Tue, 22 Nov 2016 05:48:13 GMT
Content-Type: image/gif
Content-Length: 0
Last-Modified: Wed, 06 Jan 2016 02:38:55 GMT
Connection: keep-alive ETag: “568c7e3f-0”
Accept-Ranges: bytes
Cookie:
http是面向无连接的,通过服务器返回set-cookie来设置cookie,这样下次客户端请求服务器时就可以知道上一次状态的信息。
web高速缓存代理:代理服务器:
用于保存最近的文档,这样无需访问目标服务器即可快速获得。
FTP协议:
文件传输协议(File Transfer Protocol,FTP)是Tcp/ip标准机制,用于将文件从一个主机复制到另一个主机。两个系统之间的传输需要太多约定,然而ftp简单的灵活的解决了。
在大文件传输上,ftp是更好的选择。
连接结构:
也就是FTP协议使用过程中,有两个进程被打开,控制进程,也就是21端口,用于协调控制一些操作和预定一些提前的准备,开始文件传输时使用数据传输进程。
控制传输过程中,有客户主机发送ascii字符集,一般控制的字符集作用如下:
命令 参数 说明
ABOR 放弃之前的指令
CDUP 改变到上级父目录
CWD 目录名 改变目录(类似cd)
DELE 文件名 删除目录
MKD 目录 创建目录
PASS 密码 密码
LIST 目录 列出目录下的东东
PASV 服务器选择一个端口
PORT 端口名 客户端选择一个端口
PWD 显示当前目录
QUIT 退出登陆
RETR 文件名 获取文件
RMD 目录名 删除目录
RNFR 文件名 标示一个被重命名文件
RMD 目录名 删除目录
RNTO 文件名 重命名文件
STOR 文件名 存文件
STRU F,R,P 定义数据组织(F:文件,R:记录,P:页面)
TYPE A,E,I 文件类型(A:ASCII,E:EBCDID,I:图像)
USER S,B,C 定义传输方式(S:流,B:块,C:压缩)
还有一个MODE S,B,C 定义传输方式(S:流,B:块,C:压缩)
命令发出以后,服务器端会有响应,部分响应约定如下:
编码 说明 编码 说明
125 数据连接开始 250 请求文件成功
150 文件状态良好 331 用户名成功:密码需要
200 成功 425 无法打开连接
220 服务就绪 450 文件不可用
221 服务关闭 452 动作放弃:磁盘不足
225 数据连接开始 500 语法错误:命令无效
226 关闭数据连接 501 参数变量语法错误
230 登陆成功 530 用户未登陆
数据连接:
数据连接进程中,服务器使用标准的端口20,首先有客户端发起,使用一个临时端扣被动打开数据连接。客户使用PORT命令来声明自己使用的端口,提前准备,客户端需要在数据连接开启前书名三种约定,数据结构:STRU命令定义,文件结构:TYPE命令也约定,文件类型:MODE:命令约定。
例子:
我使用的系统是Fedora(radhat系的),尝试用liunx下的ftp来获取文件:
首先ftp ip地址来连接到远程服务器
此时,需要输入用户名和密码:
完成后登陆成功,注意服务器返回的220,331,230正是上面的状态码,而ftp使用的指令已经进行了封装,常用命令如下:
ls 列出远程机的当前目录
cd 在远程机上改变工作目录
lcd 在本地机上改变工作目录
ascii 设置文件传输方式为ASCII模式
binary 设置文件传输方式为二进制模式
close 终止当前的ftp会话
hash 每次传输完数据缓冲区中的数据后就显示一个#号
get(mget) 从远程机传送指定文件到本地机
put(mput) 从本地机传送指定文件到远程机
open 连接远程ftp站点
ls命令显示超时,421状态码。
用open重新连接,并且下载一个文件
自此,完成第一个数据连接。
可想而之,即使是ls这样的命令也是遵循了上面ftp的命令规范,可以想象得到,底层必然发生了类是于:
USER hdcpptd(获取用户)
PASS ******** (输入密码)
PORT 10090 (客户端和服务器说开启数据端口10090)
TYPE EBCDIC(定义类型)
STRU R…
等等这样的ftp协议规范
邮件协议:
架构:
三个代理:
用户代理(User Agent)UA
邮件传输代理(Mail Transfer Agent)MTA
邮件访问代理(Mail Access Agent)MAA
UA可以理解为一个应用程序,假设左边发了一封邮件给右边,那么应该是这样一个架构。
这里面有两台邮件服务器,实际上发生在同一个邮件服务器上,但是流程不会变,当邮件服务器作为一端接受邮件的时候,那么此时有MTA服务器接受,然而这里面这个服务器也必须得充当客户端角色,他必须给目标发送邮件。作为邮件接受的用户,因为他的电脑并非服务器,不可能一直等待邮件到来,所以,有MAA程序发送请求去自己的邮件服务器获取邮件。
地址:
邮箱地址一般是这样
本地用户地址@邮件服务器地址
简单邮件传输协议:SMTP
MTA传输过程中使用SMTP(简单邮件传输协议),MAA(使用POP/IMAP协议)
用两种协议是因为本身这两个动作的作用是不同的,SMTP中需要定义发送地址所向,POP/IMAP主要作用就是获取,也就是自报家门。
SMTP发送中,需要一些指令协作:
协议定义了这样一些指令:
关键词 变量 说明
HELO 发送者的主机名 用于识别自身
MAIL FROM 发信人 识别发信人
RCRT TO 收信人 识别收信人
DATA 邮件主题内容 发送内容
QUIT 离开
RSET 放弃当前邮件事务
VRFY 收件人名字 验证收件人地址
NOOP 检测收件人状态
TURN 交换收件人收信人
EXPN 邮箱列表 扩增邮箱列表
HELP 以参数形式发送命令信息
SEND FROM 收信人 只发送到终端
SMOL FROM 收信人 发送到终端或者邮箱
SMAL FROM 收信人 发送到终端和邮箱
响应约定码:
肯定完成答复
211 系统状态
214 帮助报文
220 服务就绪
221 服务关闭
250 请求完成
251 用户不是本地,报文转发
肯定中间服务
354 开始邮件输入
暂时否定
421 服务不肯用
450 邮箱不可用
451 命令终止:本地错误
452 空间不足
永久否定
500 无法识别
501 参数或者变量错误
502 命令未执行
503 命令序列不正确
504 命令暂时不能执行
550 邮箱不可用
551 不用不是本地的
552
553
554 事务失败
POP和IMAP协议:
IMAP协议比pop更复杂强大
邮件传输只能发送nav7,和ascii格式报文,通过MIME协议扩展辅助以后支持非ASCII数据。
MIME协议作为头部安插在了邮件头部中