5层结构:
application 应用层
transport 传输层
network 网络层
link 数据链路层
physical 物理层
TCP: 可靠, 面向连接, 字节流传输, 点对点
UDP: 不可靠, 无连接, 数据包传输
3.3.3 http消息格式
3.3.4 Cookie技术
为什么需要cookie?
因为http协议无状态, 很多应用需要服务器掌握客户端的状态.
Cookie是为了辨别用户身份, 进行session跟踪而储存在用户本地终端上的数据
RFC6265
Cookie的组件: 4个
http响应消息的cookie头部行
http请求消息的cookie头部行
保护在客户端主机上的cookie文件, 由浏览器管理
web服务器端的后台数据库
cookie的作用:
身份认证, 购物车, 推荐, …
但是有隐私问题.
3.3.5 Web缓存技术
不访问服务器的前提下满足客户端的http请求
缩短客户请求的响应时间
减少机构的流量
在大范围内实现有效的内容分发
Web缓存/代理服务器
浏览器向缓存/代理服务器发送所有的http请求
如果所有请求对象在缓存中, 缓存返回对象. 否则, 缓存服务器向原始服务器发送http请求, 获取对象, 然后返回给客户端并保存该对象.
缓存既当客户端, 又当服务器
一般由ISP(Internet服务提供商)架设
如何保证缓存服务器是最新数据: 条件性GET方法
如果缓存有最新版本, 则不需要发送请求对象.
如果缓存的版本是最新的, 则响应消息中不包含对象. 返回HTTP/1.0 304 Not Modified
3.4.1 Email应用
SMTP协议 (Simple Mail Transfer Protocol)
消息队列message queue: 存储等待发送的email
客户端: 发送消息的服务器,
服务器: 接受消息的服务器,
SMTP协议: RFC 2821
使用TCP进行email消息的可靠传输
端口25
传输的3个阶段: 握手, 消息的传输, 关闭
命令/响应交互模式
命令(command): ASCII文本
响应(response): 状态代码和语句
email消息只能包含7位ASCII码
SMTP协议:
使用持久性连接
服务器利用CRLF.CRLF确定消息结束
与HTTP对比:
HTTP: 拉式pull
SMTP: 推push
都使用命令/响应交互模式
命令和状态码都是ASCII码
3.4.2 Email消息格式与POP协议
email可以用多个协议 与网页不同
POP: Post Office Protocol [RFC 1939] 认证/授权和下载
IMAP: Internet Mail Access Protocol [RFC 1730] 更多功能 更复杂 能够操纵服务器上存储的信息
HTTP: 163, QQmail等
事务阶段:
List: 列出消息数量
Retr: 用编号获取消息
Dele: 删除消息
Quit
IMAP: 所有消息统一保存在服务器
允许用户利用文件夹组织消息
IMAP支持跨会话(Session)的用户状态:
POP无状态-IMAP有状态
3.5.1 DNS概述
Domain Name System 域名解析系统
应用层解析: 完成名字的解析
分布式层次式数据库
DNS服务:
域名向IP地址的翻译;
主机别名;
邮件服务器别名;
负载均衡: web服务器;
为什么不使用集中式的DNS?
单点失败问题; 流量问题; 距离问题; 维护性问题;
3.5.2 DNS记录和消息格式
资源记录(resource records): RR format(name, value, type, ttl)
type=A
name: 主机域名;
value: IP地址;
type=NS
name: 域(edu.cn);
value: 该域权威域名解析服务器的主机域名;
type=CNAME
name: 某一真是域名的别名;
value: 真实域名;
type=MX
value: 是与name相对应的邮件服务器;
DNS协议:
查询(query)和回复(reply)
消息头部:
identification: 16位查询编号, 回复使用相同的编号
flags: 查询或回复; 期望递归; 递归可用; 权威回复;
questions:
answers:
authority:
additional information:
4.1.1 P2P应用 原理与文件分发
Peer to peer
没有服务器, 任意端系统之间直接通信, 节点阶段性接入Internet, 节点可能更换IP地址
缺点: 比较复杂, 难于管理
tracker: 跟踪
torrent: 流
BitTorrent
获取chunk:
Alice: 节点 定期查询每个邻居所持有的chunk列表
节点发送请求, 请求获取确实的chunk, 稀缺优先
发送chunk: tit-for-tat
Alice 向4个邻居发送chunk: 正在向其发送Chunk,速率最快的4个,每10秒重新评估top4
每30秒随机选择一个其他节点,向其发送chunk
4.1.2 P2P应用 索引
P2P系统的索引: 信息到节点位置(IP地址+端口号)的映射
文件共享过程:
利用索引动态跟踪节点所共享的文件的位置
节点需要告诉索引它拥有哪些文件
节点搜索索引, 从而获知能够得到哪些文件
即时消息过程(QQ):
索引负责将用户名映射到位置
当用户开启IM应用时,需要通知索引它的位置
节点检索索引, 确定用户的IP地址
索引有
集中式索引:
节点加入时, 通知中央服务器IP地址和内容
Alice查找内容
Alice从目标处请求文件
内容和文件传输是分布式,但是内容定位是高度集中的. 单点失效问题; 性能瓶颈; 版权问题;
洪泛式查询: Query flooding
完全分布式架构,每个节点索引只对它共享的文件进行索引
覆盖网络(overlay network) Graph
两个节点之间有TCP连接
所有的节点和边构成网络
节点转发查询消息
层次式覆盖网络: Skype
介于集中式索引和洪泛查询之间的方法
每个节点可能是一个超级节点或者被分配一个超级节点
节点和超级节点维持TCP连接
某谢超级节点之间维持TCP连接
超级节点负责跟踪子节点的内容
4.2.1 Socket编程(1)
4.2.2 Socket编程(2)
Socket API
面向TCP/IP协议栈接口 应用层
通信模型 客户/服务器 C/S
标识通信端点(对外): IP地址+端口号
定义接口sockaddr_in:
地址长度, 地址族, 端口号, IP地址, 未用
4.2.3 Socket编程(3)
使用Socket之前必须先调用WSAStartup函数
在程序完成Socket使用之后调用WSACleanup函数
socket(protofamily, type, proto)函数
第一个参数 协议族 protofamily=PF_INET (TCP/IP)
第二个参数 套接字类型 type=SOCK_STREAM, SOCK_DGRAM or SOCK_RAW
第三个参数 协议号 0为默认
Closesocket(SOCKET sd) 关闭一个sd套接字
当多个进程共享一个套接字, 调用closesocket将套接字引用计数减一, 减至0才关闭
一个进程中的多线程对一个套接字的使用无计数
int bind(sd, localaddr, addrlen) 绑定套接字的本地端点地址
IP地址+端口号
端点地址(localaddr)
客户程序一般不必要调用bind函数
如果一个服务器有多个IP地址, 用地址通配符: INADDR_ANY可解决
4.2.4 Socket编程(4)
int listen(sd, queuesize) 置服务器端的流套接字处于监听状态
仅服务器端调用
仅用于面向连接的流套接字
设置连接请求队列大小(queuesize)
返回值 0: 成功; SOCKET_ERROR: 失败
connect(sd, asddr, saddrlen) 客户端调用connect函数来对套接字进行连接
仅用于客户端 可以用于TCP客户端也可以UDP客户端
newsock = accept(sd, caddr, caddrlen) 服务端调用accept函数从处于监听状态的流套接字sd的客户连接请求队列中取出排在第一个的客户请求, 并创建一个新的套接字与客户套接字创建连接通道
仅用于TCP套接字 仅用户服务器
send(sd, *buf, len, flags) TCP套接字调用了connect函数的UDP客户端套接字
sendto(sd, *buf, len, flags, destaddr, addrlen) 用于UDP服务器套接字与未调用connect的UDP客户端的套接字
recv(sd, *buffer, len, flags) 从TCP连接的另一端接收数据, 或者调用了connect函数的UDP客户端套接字接受服务器发来的数据
recvfrom(sd, *buf, len, flags, senderaddr, saddrlen) 从UDP服务器套接字与未调用connect函数的UDP客户端套接字接收对端数据
int setsockopt(int sd, int level, int optname, * optval, int optlen)
int getsockopt(int sd, int level, int optname, *optval, socklen_t *optlen)
TCP/IP定义了标准的用于协议头的二进制整数表示: 网络字节顺序(network byte order)
某些Socket API函数的参数需要存储为网络字节顺序(如IP地址, 端口号等)
htons: 本地字节顺序 -> 网络字节顺序(16bits)
ntohs: 网络字节顺序 -> 本地字节顺序(16bits)
htonl: 本地 -> 网络(32bits)
ntohl: 网络 -> 本地(32bits)
过程…
4.2.5 Socket编程(5)
TCP客户端软件流程:
确定服务器IP地址和端口号;
创建套接字;
分配本地端点地址(IP地址+端口号);
连接服务器(套接字);
遵循应用层协议进行通信;
关闭/断开连接.
UDP客户端软件流程:
确定服务器IP地址和端口号;
创建套接字;
分配本地端点地址(IP地址+端口号);
指定服务器端点地址, 构造UDP数据报;
遵循应用层协议进行通信;
关闭/释放套接字.
4.2.6 Socket编程(6)
4种基本服务器:
循环无连接(Iterative connectionless)
循环面向连接(Iterative connection-oriented)
并发无连接(Concurrent connectionless)
并发面向连接(Concurrent connection-oriented)
循环无连接服务器基本流程:
创建套接字;
绑定端点地址(INADDR_ANY+端口号);
反复接收来自客户端的请求;
遵循应用层协议, 构造响应报文, 发送给客户.
服务器不能使用connect()函数
无连接服务器使用sendto()函数发送数据报
retcode=sendto(socket, data, length, flags, destaddr, addrlen)
调用recvfrom()函数接收数据时, 自动提取客户端点地址
循环面向连接服务器基本流程:
创建主套接字, 并绑定端口号;
设置主套接字为被动监听模式, 准备用于服务器;
调用accept()函数接收下一个连接请求, 创建新套接字用于与客户建立连接;
遵循应用层协议, 反复接收客户请求, 构造并发送响应(通过新套接字)
完成为特定客户服务后, 关闭与该客户之间的连接, 返回步骤3.
并发无连接服务器基本流程:
主线程1: 创建套接字, 并绑定端口号;
主线程2: 反复调用recvfrom()函数, 接收下一个客户请求, 并创建新线程处理该客户响应;
子线程1: 接收一个特定请求;
子线程2: 依据应用层协议构造响应报文, 并调用sendto()发送;
子线程3: 退出(一个子线程处理一个请求后即终止);
并发面向连接服务器基本流程:
主线程1: 创建主套接字, 并绑定端口号;
主线程2: 设置主套接字为被动监听模式, 准备用于服务器;
主线程3: 反复调用accept()函数接收下一个连接请求(通过主套接字), 并创建一个新的子线程处理该客户响应;
子线程1: 接收一个客户的服务请求(通过新创建的套接字);
子线程2: 遵循应用层协议与特定客户进行交互;
子线程3: 关闭连接并退出(线程终止)
服务器实现:
设计一个底层过程隐藏底层代码 passivesock()
两个高层过程分别用于创建服务器端UDP套接字和TCP套接字 passiveUDP() / passiveTCP()
5.2.1 复用和解复用
如果某层的一个协议对应直接上层的多个协议/实体, 则需要复用/分用
多路分用:
主机接收到IP数据报(datagram)
每个数据报携带源IP地址, 目的IP地址;
每个数据报携带一个传输层的段(Segment);
每个段携带源端口号和目的端口号;
主机收到Segment之后, 传输层协议提取IP地址和端口号信息, 将Segment导向响应的Socket
无连接分用:
UDP的Socket用二元组标识 目的IP地址, 目的端口号
主机收到UDP端后, 检查段中的目的端口号, 将UDP段导向绑定在该端口号的Socket
来自不同源IP地址和端口号的IP数据包被导向同一个Socket
TCP的Socket用四元组标识 源IP地址, 源端口号, 目的IP地址, 目的端口号
服务器可能同时支持多个TCP Socket, 每个Socket用自己的四元组标识
Web服务器为每个客户端开不同的Socket
5.3.1 UDP
User Datagram Protocol 用户数据报协议 RFC 768
best effort服务, UDP可能丢失, 非按序到达
发送方和接收方之间不需要握手,
好处:
减少延迟;
实现简单, 无需维护连接状态;
头部开销少;
没有拥塞控制, 应用可更好地控制发送时间和速率;
常用于流媒体应用: 容忍丢失, 速率敏感
还用于DNS, SNMP
在应用层增加可靠性机制
应用特定的错误恢复机制
报文32bits 包括:
source port, dest port, length, checksum, application data(message)
checksum 检测UDP段在传输中是否发生错误
5.4.1 可靠数据传输概述
可靠数据传输对应用层, 传输层, 链路层都很重要
信道的不可靠特性决定了可靠数据传输协议(rdt)的复杂性
只考虑单项数据传输, 但控制信息双向流动
利用状态机(Finite State Machine, FSM)刻画传输协议
rdt 1.0:
底层信道完全可靠; 不会丢弃分组;
5.4.2 rdt 2.0
利用校验和检测位错误
确认机制(Acknowledgements, ACK): 接收方显式地告诉发送方分组已正确接收;
NAK: 接收方显式地告知发送方分组有错误;
发送方收到NAK后, 重传分组;
基于这种重传机制的rdt协议成为ARQ(Automatic Repeat reQuest)协议
rdt2.0引入的新机制: 差错检测, 接收方反馈控制消息: ACK/NAK, 重传
FSM规约
停-等协议
发送方消息发出之后, 进入等待状态, 如果结果是NAK, 重发, 如果ACK,