计算机网络——自顶向下方法
应用层
(一)应用层协议原理
网络应用程序研发核心:研究如何在不同端系统上运行以及通过网络实现通信的程序
应用程序体系结构:如何在不同端系统上组织该应用程序
- 客户-服务器体系
- 对等(P2P)体系结构
1、应用程序
(1)客户-服务器体系结构
服务器是一个总是开启,并且服务很多被称为客户的主机请求的主机
特点:1.客户之间不直接通信 2.服务器有固定的、周知的地址,被称为IP地址
(2)对等(P2P)体系结构
对位于数据中心的服务器有最小的依赖性,间断连接的主机对之间直接连接进行通信,因此,这些主机对又被称为对等方
因为对等方之间的通信不需要经过专用的服务器,因此,这种体系结构又被称为对等方到对等方的
**特点:**自拓展性——在工作过程中,每个对等对在增加了系统的工作负载的同时,也提高了系统的服务能力。
成本较低——对服务器要求较低
2、进程通信
进程:可以理解为运行在端系统上的程序
进程通信:不同主机上的程序之间进行通信的过程
通信介质:运行在不同主机上的进程,通过跨越计算机网络交换**报文(message)**实现通信
(1)客户-服务器进程
在一对进程进行通信的场景中,发起请求的进程为客户,在会话开始时等待联系的进程为服务器
(2)进程与计算机网络之间的接口
进程通过**套接字(socket)**向网络发送报文以及从网络中接收报文
套接字是应用层与传输层之间的接口
套接字也被称为应用程序与计算机网络之间的应用程序编程接口(API)
(3)进程寻址
对接收进程寻址需要定义的信息:
- 主机的地址(使用IP地址进行标识)
- 在目的主机上的接收进程的标识符(目的地**端口号(port number)**进行标识)
(4)进程通信的运输服务要求
-
可靠数据传输
- 确保应用程序的一端发送的数据能够完全、准确的传输到应用程序的另一端
-
吞吐量
- 发送进程能够向接收进程交付比特的速率
- 带宽敏感的应用:对进程通信的吞吐量要求较高
- 弹性应用:对进程通信的吞吐量要求较小
-
定时
- 端到端的时延较小
-
安全性
(5)因特网提供的运输服务
因特网为进程通信提供了两种运输层协议:1.TCP 2.UDP
1.TCP服务
TCP服务包括面向连接的服务和可靠的数据传送服务
面向连接的服务是为了在进程通信双方的套接字之间建立一条TCP连接
TCP协议还具有拥塞控制机制
2.UDP服务
UDP是一种不提供不必要服务的轻量级运输协议,提供最小服务,换言之,其提供一种不可靠的数据传送服务
(6)应用层协议
应用层协议定义内容:
- 交换的报文的类型
- 各种报文类型的语法
- 字段的语义
- 确定一个进程何时发送以及如何发送报文,对报文进行响应的规则
(七)套接字编程 - 生成网络应用
典型的网络程序是由一对程序(客户端程序和服务器程序)组成的,其分别运行在不同的端系统上
网络应用的开发核心就是编写客户程序与服务器程序
1、UDP套接字编程
在发送过程中,发送进程需要为分组附上目的地址
目的地址包括目的主机的IP地址以及目的地上指定套接字的端口号
源主机的地址同样也需要附在分组上
但是该过程由底层操作系统完成
(1)UDPClient.py
//导入UDP以及TCP通信所需要的socket模块
from socket import *
//指定与客户端通信的服务器地址
//这里的hostname可以是服务器的IP地址(10.134.4.3)或者是服务器的主机名(cis.poly.edu)
serverName = 'hostname'
//指定服务器的端口号
serverPort = 12000
//创建客户的套接字clientSocket
//AF_INET 表示底层网络使用的是IPv4;SOCK_DGRAM表示创建的是一个UDP套接字
clientSocket = socket(AF_INET , SOCK_DGRAM)
//将用户输入的数据储存在变量massage中
massage = raw_input('Input lowercase sentence')
//在发送前需要将报文利用encode()方法转化为二进制
//由于使用的是UDP进行通信,因此,在客户与服务器之间并没有建立连接
//因此,在发送数据时,需要在后面加上目的主机即服务器的IP地址与指定套接字端口号
clientSocket.sendto(message.encode(),(servername, serverPoat))
//当一个报文经过因特网到达客户端主机的套接字上时,使用modifiedMessage变量将其储存
modifiedMassage, serverAddress = clientSocket.recvfrom(2048)
//将接收数据的二进制变量modifiedMessage转化为字符串并打印
print(modifiedMessage.decode())
//关闭套接字并关闭进程
clientSocket.close()
(2)UDPServer.py
from socket import *
//指定端口为12000
serverPort = 12000
//AF_INET 表示底层网络使用的是IPv4网络,SOCK_DGRAM表示创建的是UDP套接字
serverSocket = socket(AF_INET , SOCK_DGRAM)
//将端口号12000与套接字绑定在一起,这样,客户端发送数据到服务器时,就会自动导向该套接字
serverSocket.bind('', serverPort)
print("The server is ready to receive")
while true:
message, clientAddress = serverSocket.recvfrom(2048)
modifiedMessage = message.decode().upper()
serverSocket.sendto(modifiedMessage.encode(), clientAddress)
2、TCP套接字编程
(1)TCPClient.py
from socket import *
//指定服务器端口信息
serverName = 'hostname'
serverPoet = 12000
//SOCK_STREAM表示创建的是TCP套接字
clientSocket = socket(AF_INET, SOCK_STREAM)
//建立TCP连接,包含了TCP连接所需要的的三次握手,函数执行完成之后,在客户端与服务器之间建立了一条TCP连接
clientSocket.connect(serverName, serverPort)
sentence = raw_print("Input lowercase sentence")
//传输sentence字符串,注意在传输时都需要将其转化为二进制格式
clientSocket.send(sentence.encode())
//将接收的字符串储存在变量modifiedSentence中
modifiedSentence = clientSocket.recv(1024)
print("From server:", modifiedSentence.decode())
//断开TCP连接
clientSocket.close()
(2)TCPServer.py
from socket import *
serverPort = 12000
serverSocket = socket(AF_INET, SOCK_STREAM)
serverSocket.bind = ('', serverPort)
//保持服务器一直保持运行状态
serverSocket.listen(1)
print("The server is ready to receive")
while true:
//调用函数accept,创建套接字connectSocket,并且由特定的客户专用
connectSocket, addr = serverSocket.accept()
sentence = connectSocket.recv(1024).decode()
capitalizedSentence = sentence.upper()
connectSocket.send(capitalizedSentence.encode())
connectSocket.close()
3、套接字编程比较
(1) UDP与TCP的客户端比较
- 前几部都是导入库,指定服务器名字,端口以及创建套接字
- UDP的套接字为DGRAM,TCP的套接字为SOCK_STREAM
- 接下来TCP需要使用套接字的connect函数建立TCP连接,但是UDP不需要
- 下一步都是定义发送数据的变量并使用函数raw_print函数进行发送数据的输入
- 接下来是发送数据
- UDP使用的是sendto函数,其格式为套接字.sendto(要发送的变量,(服务器姓名,服务器端口))
- TCP使用的是send函数,其格式为套接字.send(要发送的变量)
- 发送数据时都要将其转化为二进制格式
- 下一步是接收数据
- UDP采用的是接收数据变量,服务器地址 = 套接字.recvfrom(2048)
- TCP采用的是接收数据变量 = 套接字.recv(1024)
- 最后是使用close函数关闭进程或者TCP连接
(2) UDP与TCP的服务器比较
-
前几步都是导入库,指定服务器端口,创建套接字并将端口分配给套接字
- TCP此时创建的是欢迎套接字,并非用来传输数据的套接字
-
接下来TCP需要使用listen(1)函数使服务器始终保持开启状态,而TCP则不需要
-
在while true里面,TCP需要首先使用欢迎套接字的accept函数创建新的套接字
-
之后与客户端相似进行数据的接收
- UDP采用的是接收数据变量,服务器地址 = 套接字.recvfrom(2048)
- TCP采用的是接收数据变量 = 套接字.recv(1024)
-
接下来是发送数据
-
UDP使用的是sendto函数,其格式为套接字.sendto(要发送的变量,(服务器姓名,服务器端口))
-
TCP使用的是send函数,其格式为套接字.send(要发送的变量)
-
发送数据时都要将其转化为二进制格式
-
-
最后TCP连接需要调用套接字的close函数关闭TCP连接
运输层
(一)运输层概述
1、运输层
运输层位置:运输层位于应用层与网络层之间
运输层功能:为运行在不同主机上的进程提供逻辑通信
- 网络层提供了不同主机上的逻辑通信
- 运输层提供了不同主机上进程的逻辑通信
运输层分组名称:报文段
2、运输层协议
协议工作位置:端系统
协议实现过程:
- 将应用报文划分为小块
- 在小快上加上运输层首部以生成运输层报文段
- 在发送端系统,运输层将生成的报文段传递给网络层
- 网络层将其封装成网络层分组(数据报)并向目的地发送
- 网络路由器仅作用于数据包的网络层字段,不检查运输层字段
- 接收端系统从数据报中提取运输层报文段并将其上交给运输层
- 运输层处理接收到的报文段,使报文段中的数据为接收应用进程使用
协议种类:TCP协议与UDP协议
- 基本责任:将两个端系统之间的IP间的交付服务拓展为运行在端系统上的两个进程之间的交付服务(又被称为运输层的多路复用与多路分解)
协议实现效果:将来自应用进程的报文移动到网络边缘(端系统)
(二)多路复用与多路分解
,运输层将生成的报文段传递给网络层
- 网络层将其封装成网络层分组(数据报)并向目的地发送
- 网络路由器仅作用于数据包的网络层字段,不检查运输层字段
- 接收端系统从数据报中提取运输层报文段并将其上交给运输层
- 运输层处理接收到的报文段,使报文段中的数据为接收应用进程使用
协议种类:TCP协议与UDP协议
- 基本责任:将两个端系统之间的IP间的交付服务拓展为运行在端系统上的两个进程之间的交付服务(又被称为运输层的多路复用与多路分解)
协议实现效果:将来自应用进程的报文移动到网络边缘(端系统)