第二章 网络应用

目录

1.网络应用体系结构

客户机/服务器(C/S):

P2P(peer to peer):

混合结构(Hybrid):

2.网络应用的服务需求

3.Internet传输层服务模型

TCP

UDP

4.特定网络应用协议

Web应用

HTTP

HTTP协议

HTTP连接

HTTP消息格式

SMTP,POP,IMAP

Email应用

SMTP协议:

Email消息格式

邮件访问协议

DNS

DNS的服务:

DNS查询示例:

DNS记录:

DNS协议与消息格式:

P2P应用

1.原理与文件分发

2.索引技术

5.Socket编程

Socket API

 


1.网络应用体系结构

客户机/服务器(C/S)

服务器:提供服务,永久域名,可扩展性

客户机:使用服务,间歇性,动态IP,不与其他客户机直接通信

P2P(peer to peer)

无永远在线的服务器,任意结点可直接通讯,间歇性,动态IP->高度可伸缩、难于管理

(存在客户机进程和服务器进程之分)

补充:P2P是指网上各台计算机有相同的功能,无主从之分,一台计算机都是既可作为服务器,设定共享资源供网络中其他计算机所使用,又可以作为工作站,没有专用的服务器,也没有专用的工作站。对等网络是小型局域网常用的组网方式。

P2P拓扑结构性能对比图:来源(https://www.cnblogs.com/linsanshu/p/5546948.html)

混合结构(Hybrid)

Napster

文件传输使用P2P结构(速度快)

文件的搜索使用C/S结构——集中式

每个节点向中央服务器登记自己的内容

每个节点向中央服务器提交查询请求,查找感兴趣的内容

2.网络应用的服务需求

可靠性/数据丢失(data loss)/可靠性(reliability)

带宽(bandwidth)

时延(delay)/时间(timing)

3.Internet传输层服务模型

TCP

面向连接:C/S进程间需建立连接

可靠的传输

流量控制

拥塞控制(网络负载过重时可限制发方的发送速度)

不提供时间延迟保障

提供最小带宽保障

UDP

无连接、不可靠、无控制

功能交给应用层实现

 

简洁对比图:

4.特定网络应用协议

Web应用

对象的寻址(addressing):

URL(Uniform Resource Locator):统一资源定位器

Scheme://host:port/path

HTTP

HTTP协议

超文本传输协议(Hypertext Transfer Protocol)

•采用客户/服务器架构

客户-Browser:请求、接收、展示web对象

服务器-Web Server:响应客户的请求,发送对象

HTTP版本:

1.0RFC 1945

1.1RFC 2068

使用TCP传输服务

无状态(stateless)

服务器不维护任何有关客户端过去所发请求的信息

HTTP连接

非持久性链接(Nonpersistent HTTP)

每个TCP连接最多允许传输一个对象

HTTP 1.0版本使用非持久性连接

分析:

 RTT(Round Trip Time):从客户端发送一个很小的数据包到服务器并返回所经历的时间

持久性链接(Persistent HTTP)

每个TCP连接允许传输多个对象

HTTP 1.1版本默认使用持久性连接

 

无流水的持久性连接

客户端只有收到前一个响应后才发送新请求

每个被引用对象耗1RTT

带流水机制的持久性连接:

HTTP1.1默认选项

客户端只要遇到一个引用对象就尽快发出请求

理想情况下,收到所有引用对象只耗时约1RTT

HTTP消息格式

1.请求消息(ASCII):

通用格式:

上传输入的方法:

POST方法:网页经常需要填写表格、在请求消息的Entity body中上传客户端的输入

URL方法:使用GET方法,输入信息通过request line的URL字段上传

其他的一些方法:

HEAD:请求Server不要将所请求的对象放入响应消息中

PUT:将消息体中的文件上传到URL字段所指定的路径(HTTP/1.1)

DELETE:删除URL字段所指定的文件(HTTP/1.1)

2.响应消息:

(status line)状态行示例:200 OK 、404 Not Found、...

3.HTTP中的Cookie技术:

 (关于Cookie的内容推荐博客:http://www.cnblogs.com/jasonwang2y60/p/6563875.html)

Cookie技术:某些网站为了辨别用户身份、进行session跟踪而存储在用户本地终端上的数据(通常经过加密)

Cookie补充:从定义上来说,Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。让我们说得更具体一些:当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器;接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体(Response Body)中的,而是存放于HTTP响应头(Response Header);当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置

Cookie中的组件:

(Cookie其实是HTTP头的一部分)

 

  Cookie的原理:

Cookie的作用:身份认证、购物车、推荐...

缺点:隐私问题;会增加宽带,增加流量消耗

SMTP,POP,IMAP

Email应用

Email应用(异步)的构成组件:

邮件客户端:读写收发信息,与服务器交互

邮件服务端:存储发给用户的Email

                     消息队列:存储等待发送的Email

SMTP协议

邮件服务器之间传递消息所使用的协议

SMTP协议:Email消息的传输/交换协议

使用TCP进行Email消息的可靠传输

端口25

传输过程的三个阶段

握手、消息的传输、关闭

命令/响应交互模式

    命令(Command): ASCII文本

    响应(Response): 状态代码和语句

Email消息只能包含7ASCII

使用持久性连接

要求消息必须由7ASCII码构成

SMTP服务器利用CRLF.CRLF确定消息的结束

HTTP对比

    HTTP: 拉式(Pull)

    SMTP: 退式(Push)

    都使用命令/响应交互模式

    命令和状态代码都是ASCII

    HTTP: 每个对象封装在独立的响应消息中

    SMTP: 多个对象在由多个部分构成的消息中发送

Email消息格式

RFC 822文本消息格式标准

    头部(Header):

        To

        From

        Subject

    消息体(Body)

        消息本身

        只能是ASCII字符

MIME:多媒体邮件扩展

    通过在邮件头部增加额外行以声明MIME的内容类型

邮件访问协议

从服务器获取邮件

POPPost Office Protocol

        认证/授权(客户端<——>服务器)和下载

POP协议模式:

(1)下载并删除模式

          用户如果换了客户端软件,无法重读该邮件

(2)下载并保持模式:不同客户端都可以保留消息的拷贝

(3)POP是无状态的

IMAPInternet Mail Access Protocol

    更多功能、更加复杂

    能够操纵服务器上存储的消息

(1)所有消息保存在服务器

(2)允许用户利用文件夹组织消息

(3)支持跨会话(Session)的用户状态:文件夹的名字、文件夹与消息ID之间的映射等

HTTP163QQ Mail等,通过浏览器使用邮箱

DNS

解决Internet上主机/路由器的识别问题.(在网络应用层实现)

域名解析系统DNS(Internet核心功能):IP地址<->域名

1、由多层命名服务器构成的分布式数据库

2、应用层协议:完成名字的解析

DNS的服务

1、域名向IP地址的翻译

2、主机别名

3、邮件服务器别名

4、负载均衡:web服务器(?)

问题:为什么不使用集中式的DNS?

1、单点失败问题

2、流量问题->流量大、成本高

3、距离问题->RTT大

4、维护性问题

分布式层次式数据库示意图:

运作过程:

根域名服务器(Root DNS Servers):

本地域名解析服务器无法解析域名时,需要访问根域名服务器。若根域名服务器不知道IP映射,则需访问权威服务器,从而获得映射,接着向本地域名服务器返回映射。

顶级域名服务器TLD(top-level domain):负责com,org,net,edu等,国家顶级域名:如cn,uk,fr等。

权威域名服务器:组织的域名解析服务器,提供组织内部服务器的解析服务。可由组织自身负责维护或者服务提供商负责维护。

本地域名解析服务器:每个ISP(Internet Server Provider)都有一个本地域名服务器(默认域名解析服务器)。当主机进行DNS查询时,本地域名服务器作为代理,会将查询转发给层级时的域名解析服务器系统。

补充:

 

DNS查询示例:

迭代查询:

 

递归查询:

 

DNS记录缓存和更新:

只要域名解析服务器获得域名-IP映射,即缓存这一映射;本地域名服务器一般会缓存顶级域名服务器的映射

 

DNS记录:

资源记录RR(resource records)

fomat:(name,value,type,ttl)

Type=A:

    Name:主机域名

    Value:IP地址

Type=NS:

    Name:域

    Value:该域权威域名解析服务器的主机域名

Type=CNAME:

    Name:某一真实域名的别名

    Value:真实域名

Type=MX:

    Value是与name相对应的邮件服务器

DNS协议与消息格式:

DNS协议:

    查询/回复

    消息格式(查询/回复格式相同):

详细解析推荐博客:https://blog.csdn.net/tianxuhong/article/details/74922454

 

DNS->TCP or UDP?

注册域名

P2P应用

1.原理与文件分发

文件分发对比

客户机/服务器

P2P

服务器串行地发送N个副本

时间:NF/Us

 

客户机i需要F/di时间下载

 

Max{NF/Us, F/min(di)}

服务器必须发送一个副本

时间:F/Us

客户机i需要F/di时间下载

总共需要下载NF比特

互相分享,最快可能上传速率:Us+Σui

Max{F/Us, F/min(di), NF/(Us+Σui)}

 

客户端上传速率=UF/U=1小时,Us=10U,dmin>=Us.

客户端/服务器随N线性增长

P2PN增长趋于稳定

对比结果

文件分发:BitTorrent:

•文件划分为256KB的chunk

•节点加入torrent

没有chunk,但是会逐渐积累;

向tracker注册以获得节点清单,与某些节点(“邻居”)建立连接

•下载的同时,节点需要向其他节点上传chunk

•节点可能加入或离开

•一旦节点获得完整的文件,它可能(自私地)离开或(无私地)留下

 

获取chunk

  给定任一时刻,不同的节点持有文件的不同chunk集合

  节点(Alice)定期查询每个邻居所持有的chunk列表

  节点发送请求,请求获取缺失的chunk(稀缺优先)

发送chunk: tit-for-tat(一报还一报)

  Alice4个邻居发送chunk: 正在向其发送Chunk, 速率最快的4个。

  10秒重新评估top 4

  30秒 随机选择一一个其他节点,向其发送chunk

  新选择节点可能加入top 4

  “optimistically unchoke"

思考题:BitTorrent技术对网络性能有哪些潜在的危害?

答:答案参考https://zhidao.baidu.com/question/2078727157674570108

硬盘的损害。BT三大指控:高温、重复读写、扇区断块;对网络带宽的损害;助长了病毒的传播;可能面临着版权侵害的风险

2.索引技术

P2P系统的索引:信息到节点位置(IP地址+端口号)的映射

例如:文件共享(电驴)

例如:即时消息(QQ)

 

一、集中式索引

Napster最早采用这种设计

1)节点加入时,通知中央服务器:

  IP地址

  内容

2) Alice查找“Hey Jude”

3) Alice从Bob处请求文件

缺点:

内容和文件传输是分布式的,但是内容定位是高度集中式的。

•单点失效问题

•性能瓶颈

•版权问题

二、洪泛式查询:Query flooding

•完全分布式架构

•Gnutella采用这种架构

•每个节点对它共享的文件进行索引,且只对它共享的文件进行索引

 

利用覆盖网络进行洪泛式搜索。什么是覆盖网络?

覆盖网络(overlay network): Graph

节点XY之间如果有TCP连接, 那么构成一个边

所有的活动节点和边构成覆盖网络

;虚拟链路

节点一般邻居数少于10

 

洪泛式查询工作原理:

查询消息通过已有的TCP连接发送

节点转发查询消息

如果查询命中,则利用反向路径发回查询节点

洪泛式查询缺点:

像洪水一样泛滥,给网络带来很大负担。大量消耗网络带宽,导致网络拥塞。

节点刚加入时需要复杂的处理。

 

三、层次式覆盖网络

介于集中式索引和洪泛查询之间的方法

•每个节点或者是一个超级节点,或者被分配一个超级节点

    1)节点和超级节点间维持TCP连接;

    2)某些超级节点对之间维持TCP连接。

•超级节点负责跟踪子节点的内容

 

案例应用:Skype

本质上是P2P:用户/节点对之间直接通信

私有应用层协议

采用层次式覆盖网络架构

索引负责维护用户名与IP地址间的映射

索引分布在超级节点上

5.Socket编程

Socket API

网络程序设计接口

Socket API:

标识通信端点(对外) :IP地址+端口号

操作系统/进程管理套接字(对内) :套接字描述符(socket descriptor)

 

Socket抽象:

类似于文件的抽象

当应用进程创建套接字时,操作系统分配一个数据结构存储该套接字相关信息

返回套接字描述符

地址结构:

Socket API函数(WInSock):

WSAStartup

int WSAStartup(WORD wVersionRequested, LPWSADATA IpWSAData);

Socket的应用程序在使用Socket之前必须首先调用该函数;

两个参数:

第一个参数:指明程序请求使用的WinSock版本,其中,高位字节指明副版本号、低位字节指明主版本。如0x102表示2.1版

第二个参数:返回实际的WinSock版本信息,指向WSADATA结构的指针

:使用2.1 版本的WinSock的程序代码段

  wVersionRequested = MAKEWORD(2, 1 );

  err = WSAStartup( wVersionRequested, &wsaData );

WSACleanup

int WSACleanup (void)

应用程序完成对Socket库的使用后,最后要调用WSACleanup函数->解除与Socket库的绑定,释放Socket库占用的系统资源

 

socket:

sd = socket(protofamily,type,proto);

调用socket创建套接字,操作系统返回套接字描述符(sd)

第一个参数(协议族):protofamily= PF_ INET (TCP/IP),判断是面向什么协议的。

第二个参数(套接字类型):type = SOCK_STREAM,SOCK_ DGRAM or SOCK_ RAW (TCP/IP)

第三个参数(协议号):0为默认

 

创建一个流套接字的代码段

struct protoent *p;   p=getprotobyname("tcp");

SOCKET sd=socket(PF_ INET,SOCK_ STREAM,p->p_ _proto);

 

 其中,第二个参数的具体应用:

 

 

 

Closesocket:

int closesocket(SOCKET sd);

性质:

 

关闭一个描述符为sd的套接字

如果多个进程共享一一个套接字,调用closesocket将套接字引用计数减1,减至0才关闭

一个进程中的多线程对一个套接字的使用无计数.

    如果进程中的一个线程调用closesocket-一个套接字关闭,  该进程中的其他线程也将不能访问该套接字

返回值:

      0:  成功

      SOCKET_ ERROR:失败

bind:

int bind (sd, localaddr,addrlen) ;

绑定套接字的本地端点地址

    IP地址+端口号

参数:

    套接字描述符(sd)

•    端点地址(localaddr)

      结构sockaddr_ in

客户程序一般不必调用bind函数

服务器端

    熟知端口号

    IP地址:绑定服务器运行的主机的IP地址

 

在不同的网络中拥有不同的IP地址->通过 地址通配符 INADDR_ANY解决,不应该指定确定的IP地址

listen

int listen (sd, queuesize) ;

置服务器端的流套接字处于监听状态

  仅服务器端调用

  仅用于面向连接的流套接字

设置连接请求队列大小(queuesize)

  当有很多请求到达时,就存放到队列中缓存,再从队列中一一提取。

返回值:

  0:成功

  SOCKET_ ERROR:失败

connect

connect ( sd, saddr , saddrlen)

•客户程序调用connect函数来使客户套接字(sd)与特定计算机的特定端口(saddr) 的套接字(服务)进行连接心

仅用于客户端

•可用于TCP客户端也可以用于

UDP客户端

TCP客户端:建立TCP连接

UDP客户端:指定服务器端点地址

 

accept:

newsock = accept (sd, caddr,caddrlen);

服务程序调用accept函数从处于监听状态的流套接字sd的客户连接请求队列中取出排在最前的一个客户请求,并且创建一一个新的套接字来与客户套接字创建连接通道

    1)仅用于TCP套接字

    2)仅用于服务器

利用新创建的套接字

(newsock)与客户通信

利于实现并发TCP服务器

 

 

send,sendto

send (sd, *buf ,len, flags) ;

sendto (sd, *buf len, flags , des taddr , addrlen) ;

•send函数TCP套接字(客户与服务器)或调用了connect函数的UDP客户端套接字

•sendto函数用于UDP服务器端套接字与未调用connect函数的UDP客户端套接字

recv,recvfrom:

recv (sd, *buffer,len, flags) ;

recvfrom sd, *buf,len , flags,senderaddr,saddrlen) ;

recv函数从TCP连接的另一端接收数据,或者从

调用了connect函数的UDP客户端套接字接收服务器发来的数据

recvfrom函数用于从UDP服务器端套接字与未调

connect函数的UDP客户端套接字接收对端数据

setsockopt,getsockopt:

int setsockopt(int sd, int level, int optname, *optval, int optlen);

int getsockopt(int sd, int level, int optname, *optval, socklen_ t *optlen);

•setsockopt()函数用来设置套接字sd的选项参数

• getsockopt()函数用于获取任意类型、任意状态套接口的选项当前值,并把结果存入optval

小节:

WSAStartup:初始化socket(仅对WinSock)

WSACleanup:清楚/终止socket库的使用(仅对WinSock)socket:创建套接字

connect:“连接”远端服务器(仅用于客户端)closesocket.释放/关闭套接字

bind:绑定套接字的本地IP地址和端口号(通常客户端不需要)

listen:置服务器端TCP套接字为监听模式,并设置队列大小(仅用于服务器端TCP套接字)

accept:接受/提取一个连接请求,创建新套接字,通过新套接(仅用于服务器端的TCP套接字)

recv:接收数据(用于TCP套接字或连接模式的客户端UDP套接字)

recvfrom:接收数据报(用于非连接模式的UDP套接字)

send:发送数据(用于TCP套接字或连接模式的客户端UDP套接字)

sendto:发送数据报(用于非连接模式的UDP套接字)

setsockopt:设置套接字选项参数

getsockopt:获取套接字选项参数

 

 

 

网络字节顺序:

TCP/IP定义了标准的用于协议头中的二进制整数表示:网络字节顺序(network byte order)

某些SocketAPI函数的参数需要存储为网络字节顺序(IP地址、端口号等)

可以实现本地字节顺序与网络字节顺序间转换的函数

htons:本地字节顺序-→网络字节顺序(16bits)

ntohs:网络字节顺序- +本地字节顺序(16bits)

htonl:本地字节顺序- >网络字节顺序(32bits)

ntohl:网络字节顺序_本地字节顺序(32bits)

 

SocketAPI 调用基本流程:

 

客户端软件设计

解析服务器IP地址:

IP协议需要使用32位二进制IP地址。

将域名或IP地址转换位32位IP地址的函数:

1)函数inet_ add( )实现点分十进制IP地址到32IP地址转换

    2)函数gethostbyname( )实现域名到32IP地址转换

  返回一个指向结构hostent的指针

 

 

解析服务器(熟知)端口号:

将服务名(如http)转换为熟知端口号的函数:

解析协议号:

需要将协议名转换为协议号:

 

TCP客户端软件流程

UDP客户端软件流程

1.确定服务器IP地址与端口号

2.创建套接字

3.分配本地端点地址(IP地址+端口号)

4.连接服务器(套接字)

5.遵循应用层协议进行通信

6.关闭/释放连接

1.确定服务器IP地址与端口号

2.创建套接字

3.分配本地端点地址(IP地址+端口号)

4.指定服务器端点地址,构造UDP数据报

5.遵循应用层协议进行通信

6.关闭/释放套接字

客户端软件的实现-connectsock()

 

客户端软件的实现-UDP客户端

 客户端软件的实现-TCP客户端:

 

客户端软件的实现-异常处理

 

例:

访问DAYTIME服务的客户端(TCP):

(数据流传输)

访问DATTIME服务的客户端(UDP):

(数据报传输)

MSG:给DAYTIME服务器发送的消息

 

服务器软件设计

基于套接字编程的服务器端软件设计:

4种类型基本服务器:

循环无连接(Iterative connectionless)服务器

循环面向连接(terative connection-oriented)服务器

并发无连接(Concurrent connectionless)服务器

并发面向连接(Concurrent connection-oriented)服务器

 

循环无连接服务器基本流程:

1.创建套接字

2.绑定端点地址(INADDR_ ANY+端口号)

3.反复接收来自客户端的请求

4.遵循应用层协议,构造响应报文,发送给客户

 

 

数据发送:

 

服务器端不能使用connect()函数

无连接服务器使用sendto()函数发送数据报

retcode=sendto (socket , data , length , flags , destaddr , addrlen) ;

注释:

socket:服务器(UDP)套接字

data:存储待发送数据缓存的地址

length:缓存中数据字节数

flags:调试或控制选项

destaddr:指向結枸sockaddr_ in的指籵(客戸端端点地址)

addrlen:地址结构长度

 

客户的端点地址在调用recvfrom()函数接收数据时 自动提取:

 

retcode=recvf com ( socket ,buf , length, flags , from, fromlen) ;

注释:

socket : (UDP)服务器套接字

buf:存放数据报的缓存地址

length:缓存可用空间

flags:调试或控制选项

from:存放源地址的缓存地址

fromlen:源地址长度

 

 循环面向连接服务器的基本流程:

1.创建()套接字,并绑定熟知端口号;

2.设置()套接字为被动监听模式,准备用于服务器;

3. 调用accept()函数接收下一一个连接请求(通过主套接字),创建新套接字用于与该客户建立连接;

4. 遵循应用层协议,反复接收客户请求,构造并发送响应(通过新套接字);

5. 完成为特定客户服务后,关闭与该客户之间的连接,返回步骤3.

 

并发无连接服务器基本流程:

主线程1:创建套接字,并绑定熟知端口号;

主线程2:反复调用recvfrom()函数,接收下一个客户请求,并创建新线程处理该客户响应;

子线程1:接收一个特定请求;

子线程2:依据应用层协议构造响应报文,并调用sendto()发送;

子线程3:退出(一个子线程处理-一个请求后即终止)

 

并发面向连接服务器的基本流程:

主线程1:创建()套接字,并绑定熟知端口号;

主线程2:设置()套接字为被动监听模式,准备用于服务器;

主线程3:反复调用accept()函数接收下一一个连接请求(通过主套接字),并创建一一个新的子线程处理该客户响应;

子线程1:接收一一个客户的服务请求(通过新创建的套接字) ;

子线程2:遵循应用层协议与特定客户进行交互;

子线程3:关闭/释放连接并退出(线程终止).

 

 

服务器的实现:

 

passivesock:

 

passiveUDP():

passiveTCP():

 

(同时参考https://www.cnblogs.com/cellphone7/p/9520438.html,十分感谢)