网络体系结构标准
OSI模型
- 1、网络信息传输比较复杂需要很多功能协同。
- 2、将功能分开,降低耦合度,让每个模块完成一定的功能。
- 3、将这些模块按照一定的顺序进行组合,完成功能,条理清晰。
按照规定功能、顺序排列的体系结构,即为OSI模型。
七层模型
- 应用层
提供用户服务,例如处理应用程序、文件传输、数据管理等。 - 表示层
数据的转换和压缩、解压的加密等。 - 会话层
决定了进程间的连接建立,选择使用了什么样的传输协议。 - 传输层
建立网络连接,提供合适的连接传输服务,提供流量控制。 - 网络层
控制分组传输,进行路由选择,网络互联。 - 链路层
提供链路交换,具体的数据收发。 - 物理层
物理硬件,具体的传输条件和传输接口。
四层
- 应用层(应用层、表示层、会话层)
- 传输层
- 网路层
- 物理链路层(链路层、物理层)
五层(TCP/IP模型)
- 应用层(应用层、表示层、会话层)
- 传输层
- 网路层
- 链路层
- 物理层
网络协议
在网络传输过程中,为了保证通信的正常而制定的都遵守的约定。
应用层协议
TFTP、DNS、FTP、SMTP、HTTP
传输层协议
TCP、UDP
网络层协议
IP、ARP、ICMP
物理链路层协议
IEEE
主机
主机名称
计算机名、域名,仅限于本地,用不了互联网。
本地主机表示方法:IP
表示本机在网络上的定位。
-
localhost
或127.0.0.1
:表示本机通信地址。只有本机的其他程序可以访问,网络访问不了,也可叫本机回环地址,可用于本地模拟测试。 - IP地址:表示本机在网络上的标识,可用于网络。
0.0.0.0
:表示在局域网内的可用主机IP,如果不知道本机的IP,可用0.0.0.0
表示给本主机分配一个局域网内随机可用IP。
相关函数
// 导入相关模块
import scoket
// 获取主机名称
socket.gethostname()
// 通过主机名称解析本机或主机服务器IP
socket.gethostbyname('hostname')
// 解析本机localhost回环IP
socket.gethostbyname('localhost')
/*
* 查看主机的信息,返回一个元组
* 第一个参数表示主机名
* 第二个参数表示主机别名
* 第三个参数表示主机地址
* args可以是IP或域名
*/
socket.gethostbyaddr('args')
IP地址
指一台计算机在互联网中的标志
IPv4
表示方法
- 点分十进制
三个点将IP分为四个部分,每部分取值0~255
例如:192.168.1.5
,192.121.10.23
,172.23.5.6
... - 二进制
32位二进制表示
IPv6
- 随着网络的发展,IPv4地址不够用了,为了扩展地址空间,研究出了IPv6。
- IPv6为128位,用十六进制表示,两个十六进制占一组,大大扩展了地址空间。
- 在我国,大部分的民用地址还是IPv4,有些商用地址是IPv6。
192.168.1.0
表示该网段
192.168.1.1
该网段的网关地址
192.16.1.255
广播地址
ping命令
查看是否可以访问某台主机
IP地址的转换
/*
socket.pton()与socket.ntop()有第一个参数
AF_INET表示转化IPv4类地址
AF_INET6表示转化IPv6类地址
其余和socket.inet_aton()与socket.inet_ntoa()功能相同
*/
// 将点分十进制转换为二进制
socket.inet_aton('192.168.12.23') // b'\xc0\xa8\x0c\x17'
socket.inet_pton(socket.AF_INET,'192.168.12.23') // b'\xc0\xa8\x0c\x17'
// 将二进制转换为点分十进制
socket.inet_ntoa(b'\xc0\xa8\x0c\x17') // 192.168.12.23
socket.inet_ntop(socket.AF_INET,b'\xc0\xa8\x0c\x17') // 192.168.12.23
域名
互联网服务器IP的名字,方便使用
端口号
地址的组成部分,用于在一个系统中区分应用层程序
取值范围:1~65536
1 ~ 255
众所周知的端口,一些特有的程序会占用这些端口
256 ~ 1023
系统程序占用的端口
1024 ~ 49151
登记端口(可以使用)
49152 ~ 65535
私有端口或者动态端口
推荐使用10000
以上的端口号
获取系统中某个网络服务程序的端口号
// 获取系统中某个网络服务程序的端口号
socket.getservbyname('ssh') // 22
socket.getservbyname('mysql') // 3306
socket.getservbyname('http') // 80
子网掩码
与IP配合使用,来确定当前的网段。
按位相与即可得到当前网段。
字节序
- 小端序:低序字节存在低地址位
- 大端序:高序字节存在低地址位
- 网络统一:网络字节序,保证不同的主机按照相同方式发送接收解析数据
TCP/UDP协议
传输层提供的通信协议
面向连接的可靠服务(TCP协议)
-
TCP协议规定:
- 传输服务必须建立连接
- 传输结束必须断开连接
- 传输数据必须保证可靠
-
建立连接(三次握手)
- 客户端向服务端发送连接请求(发送一个试探性的标志字符给服务器)
- 服务器端接收到请求后告知客户端可以连接
- 再次告知服务器客户端已经收到回复,下面开始发送具体的消息
-
数据的可靠性
- 无重复
- 无丢失
- 无失序
- 无错误
-
断开连接(四次挥手)
- 主动方送标志告知被动方要断开来连接
- 被动方返回相应的标志信息告知主动方已经收到断开请求
- 被动方会再次发送标志位信息表示已经准备就绪可以断开
- 主动方断开连接告知被动方
-
适用情况
- 对传输质量要求较高,需要可靠的传输。
- 传输的数据量较大,不需要频繁的连接断开
比如:QQ消息、邮件收发、文件上传、账户登陆等
面向无连接的不可靠服务(UDP协议)
-
特点
- 不保证数据的完整性
- 数据的发送都是由发起端决定的,不考虑接收端的情况
- 没有三次握手和四次挥手的过程
-
适用情况
- 对实时性要求较高
- 网络情况不佳的时候
- 对数据的准确性没有严格要求
- 建立必要的非连接的情况(比如:广播组播)
套接字
网络间进行通信的方式的名称。
在linux中演化为一种文件类型。
套接字的分类
流式套接字
表示传输层使用TCP协议提供面向连接的传输服务,以字节流形式进行传输
数据报套接字
表示传输层使用UDP协议提供面向无连接的传输服务,以消息结构体形式进行传输
原始套接字
一般用于底层测试(一般用不到)
基于TCP协议的socket编程
服务端
-
创建一个TCP流式套接字
socket(family = AF_INET,type = SOCK_STREAM,proto = 0)
- 功能:创建一个套接字
- 参数:
-
family
协议族类型(AF_INET、UNIX)
-
type
套接字类型
SOCK_STREAM
TCP流式套接字
SOCT_DGRAM
UDP数据报套接字
SOCK_RAM
原始套接字 -
proto
自协议类型 一般为0
-
- 返回值:套接字对象
-
绑定本机的IP和端口号
bind(address)
- 功能:邦定本机的IP和端口号
- 参数:一个包含两个元素的元组,元组第一个元素是主机名,第二个是使用的端口号
-
将套接字变为可监听套接字
listen(n)
- 功能:
- 将套接字设置为监听套接字,让套接字可以去接受多个客户端的连接请求
- 设置一个连接等待队列
- 参数:是一个正整数
>=1
- 功能:
-
套接字等待客户端请求
accept()
- 功能:阻塞等待客户端的连接
- 参数:无
- 返回值:
- 第一个返回值为和客户端交互的新的套接字
- 第二个返回值为连接进来的客户端的address
-
消息的收发
recv(buffer)
- 功能:接受网络消息
- 参数:正整数,表示一次接受从缓冲区中拿到的消息的字节数
- 返回值:返回接收到的消息
- 当接收的网络缓冲中没有内容时会阻塞
-
当连接断开后,
recv
会结束阻塞返回一个空字串
send(data)
- 功能:发送网络消息
- 参数:要发送的内容
- 返回值:实际发送的字节数
- python3中要求
send
的内容必须为bytes
格式
sendall(data)
- 功能:发送网路消息
- 参数:要发送的内容要求为
bytes
格式 - 返回值:如果成功发送返回
None
,发送失败报异常
-
关闭套接字
客户端
connect(address)
- 功能:向服务器发起连接请求
- 参数:address是一个元组,即为要连接的服务器的地址
- 注意点:
- 客户端要和服务器端的套接字类型相同
- 客户端就是用创建的套接字和服务器交互
-
recv
和send
要与服务器配合,避免recv
死阻塞
TCP循环服务不能满足多个客户端同时发送请求的情况,它不允许多个单个客户端单独长期占有服务器资源
TCP数据传输
recv
会不断取出接受缓冲区中的内容,如果一次没有拿完,那么下次回继续收取没拿完的消息
TCP粘包
- TCP粘包指的是发送方发送若干次数据的时候,因为是数据流的传输方式,导致数据粘连在一起,接受方一次将多次发送的数据一起接受,产生接受数据的粘连。
- 粘包是TCP传输特有的现象,因为TCP传输没有消息边界。
- 如果是发送连续的内容,比如文件等则粘包没有影响。如果是每次发送为单独需要处理的内容则要处理粘包。
处理粘包现象
- 将消息个格式化
- 发送消息的同时发送一个消息长度标志
- 让消息的发送延迟,使接受端每次都能够有时间接受一个消息
#!/usr/bin/python3
# argv.py
import sys
// 将命令行内容收集为一个列表,每一个元素是命令行中的一项
print(sys.argv)
// ./argv.py ab cd
print(sys.argv) // ['argv.py','a','b']
基于UDP协议的socket编程
服务端
- 创建数据包套接字
- 绑定本地IP和端口
- 收发消息
- 关闭套接字
客户端
- 创建数据包套接字
- 收发消息
- 关闭套接字
相关函数
recvfrom(BUFFERSIZE)
- 功能:在UDP中接受消息
- 参数:
BUFFERSIZE
表示一次最多可以接受多少自己的消息 - 返回值:
data
接受到的消息
addr
表示从哪个客户端接收到的消息 - 每次只能接受一个数据包,如果数据包的大小超过
recvfrom
的设置大小则会出现数据丢失
sendto(data,addr)
- 功能:向一个网络终端发送消息
- 参数:
data
要发送的消息(bytes)
addr
发送对象的地址
TCP于UDP的区别
- TCP是有连接的,UDP是无连接的
- TCP有三次握手四次挥手的过程,UDP没有
- TCP是以数据流传输数据,会有粘包,UDP是数据报的形式没有粘包
- TCP的连接需要消耗一定的资源,相比之下UDP资源消耗少
- TCP保证数据的可靠性,UDP不保证
- TCP需要
listen
,accept
,connect
,UDP不需要
套接字属性
sock = socket.socket()
-
sock.getpeername()
用作服务器连接套接字,查看连接的客户端地址 -
sock.getsockname()
获取套接字对应绑定的地址和端口 -
sock.type
获取套接字的类型 -
sock.fileno()
获取套接字的文件描述符号码。
系统会给进程中每个IO操作对象分配一个>=0的正整数作为标号,我们称之为该IO操作的文件描述符。一个进程中所有IO的文件描述符不会重复。 -
sock.setsockopt(level,optname,value)
功能:设置套接字选项,可以增加或改变套接字的功能
参数:
level
要定义的选项类型
optname
每种类型都有具体的选项,根据具体的需求选择选项进行设置
value
将选择的选项设置为什么值 -
getsockopt(level,optname)
功能:获取相应选项的值
参数:
level
要获取的选项类型
optname
每种类型都有具体的选项,根据具体的需求选择要获取的选项
返回值:获取到的值
网友评论