一、网络基础
网络建立的目的是为了数据交互(通信)
如何实现通信:
1.建立好底层的物理连接介质
2.有一套统一的通信标准,称之为互联网协议
1.osi七层协议
互联网协议按照功能的不同分为osi七层或tcp/ip五层或tcp/ip四层
每层运行的常见物理设备
2.tcp/ip五层协议模型讲解
2.1物理层:主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0
2.2数据链路层:定义了电信号的分组方式,由于单纯的0和1并没有任何意义,必须规定电信号多少位一组,每组什么意思
以太网协议:
早期每个公司都有自己的分组方式,后来形成统一的标准,即以太网协议Ethernet
Ethernet规定
1.一组电信号构成一个数据包,叫做‘帧’,每一数据帧分成:报头head和数据data两部分
2.报头(head):固定字节数,里面包含发送者,接收者,数据类型。数据(data):数据包的具体内容
mac地址
head中包含的源和目标地址的由来:以太网规定接入internet的设备都必须具备网卡,发送地址和接收地址都是通过网卡来的
每块网卡出厂时都被烧制上一个唯一的mac地址,前6位是厂商编号,后6位是流水线号
广播:
有了mac地址,同一网络内的两台计算机就可以通信了
2.3网络层:不同网络内想要通信,光靠Ethernet、mac地址和广播并不可行,所以引入一套新的地址用来区分不同的网络,这套地址就叫网络地址
ip协议:
规定网络地址的协议叫ip协议,它定义的地址称为ip地址,广泛采用v4版本即ipv4,它规定网络地址由32位2进制表示
范围为0.0.0.0 ---255.255.255.255
ip地址分为两部分
网络部分:标识子网
主机部分:标识主机
子网掩码:
形式上等同于ip地址,也是32位二进制,网络部分全部为1,主机部分全为0。
知道子网掩码我们就能判断,任意两个ip地址是否处在同一个子网络。方法是将两个ip地址分别进行AND运算(两个都为1运算结果为1,否则为0),比较结果是否相同,如果相同的话就表明他们是在一个子网络中,否则就不是
总结ip协议的作用:1.为每台计算机分配ip地址,2确定这些地址是不是在同一个子网络中。
ARP协议
广播的方式发送数据包,获取目标主机的mac地址
2.4传输层:网络层的ip帮我们区分子网,以太网层的mac帮我们找到主机,传输层建立端口到端口的通信,端口就是应用程序与网关关联的编号 端口范围0-65535, 0-1023位系统占用端口
tcp协议:可靠传输,tcp数据包没有长度限制,必须等到有回应才会继续发送
udp协议:不可靠传输,不管有没有收到响应只管发送
tcp的三次握手
注:TCP的TIME_WAIT需要等待2MSL,当TCP的一端发起主动关闭,三次挥手完成后发送第四次挥手的ACK包后就进入这个状态,等待2MSL时间主要目的是:防止最后一个ACK包对方没有收到,那么对方在超时后将重发第三次握手的FIN包,主动关闭端接到重发的FIN包后可以再发一个ACK应答包。在TIME_WAIT状态时两端的端口不能使用,要等到2MSL时间结束才可以继续使用。当连接处于2MSL等待阶段时任何迟到的报文段都将被丢弃。MSL即Maximum Segment Lifetime,就是最大报文生存时间,是任何报文在网络上的存在的最长时间,超过这个时间报文将被丢弃。
常见面试题:为什么建立链接是三次握手,不是二次,四次,关闭链接却是四次不是其它
这是因为服务端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,当收到对方的FIN报文时,仅仅表示对方不再发送数据了但是还能接收数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。
2.5应用层:规定应用程序的数据格式
二、socket介绍
socket是应用层与tcp/ip协议通信的中间软件抽象层,它是一组接口,它吧复杂的TCP/IP协议隐藏在socket接口后面。
基于文件类型的套接字家族:
套接字家族的名字:AF_UNIX
unix一切皆文件,基于文件的套接字调用的就是底层的文件系统来取数据,两个套接字进程运行在同一机器,可以通过访问同一个文件系统间接完成通信
基于网络类型的套接字家族:
套接字家族的名字:AF_INET
AF_INET被用于ipv4,AF_INET6被用于ipv6
三、套接字使用
import socket socket.socket(socket_family,socket_type,protocal=0) socket_family 可以是 AF_UNIX 或 AF_INET。socket_type 可以是 SOCK_STREAM 或 SOCK_DGRAM。protocol 一般不填,默认值为 0。 获取tcp/ip套接字 tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 获取udp/ip套接字 udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 由于 socket 模块中有太多的属性。我们在这里破例使用了'from module import *'语句。使用 'from socket import *',我们就把 socket 模块里的所有属性都带到我们的命名空间里了,这样能 大幅减短我们的代码。 例如tcpSock = socket(AF_INET, SOCK_STREAM)
客户端套接字函数
s.connect() 主动初始化TCP服务器连接
s.connect_ex() connect()函数的扩展版本,出错时返回出错码,而不是抛出异常
公共用途的套接字函数
s.recv() 接收TCP数据
s.send() 发送TCP数据(send在待发送数据量大于己端缓存区剩余空间时,数据丢失,不会发完)
s.sendall() 发送完整的TCP数据(本质就是循环调用send,sendall在待发送数据量大于己端缓存区剩余空间时,数据不丢失,循环调用send直到发完)
s.recvfrom() 接收UDP数据
s.sendto() 发送UDP数据
s.getpeername() 连接到当前套接字的远端的地址
s.getsockname() 当前套接字的地址
s.getsockopt() 返回指定套接字的参数
s.setsockopt() 设置指定套接字的参数
s.close() 关闭套接字
面向锁的套接字方法
s.setblocking() 设置套接字的阻塞与非阻塞模式
s.settimeout() 设置阻塞套接字操作的超时时间
s.gettimeout() 得到阻塞套接字操作的超时时间
面向文件的套接字的函数
s.fileno() 套接字的文件描述符
s.makefile() 创建一个与该套接字相关的文件
基于tcp协议通信的套接字简单
from socket import socket, AF_INET, SOCK_STREAM # socket 套接字 # AF_INET IPv4 # SOCK_STREAM socket流 IP = "127.0.0.1" PORT = 8888 ADDRESS = (IP, PORT) BUFSIZE = 1024 print("服务器开启了") # 1.创建服务器socket对象 serSocket = socket(AF_INET, SOCK_STREAM) # 2.设置服务器地址 serSocket.bind(ADDRESS) # 3.设置连接管理队列 serSocket.listen(5) # 4.建立客户端服务器连接 cliSocket, addr = serSocket.accept() print(cliSocket) print(addr) # 5.收发数据 data = cliSocket.recv(BUFSIZE) print(data.decode("utf-8")) cliSocket.send("服务器返回的数据".encode("utf-8")) # 6.断开客户端 cliSocket.close() # 7.关闭服务器 serSocket.close() print("服务器关闭了")
from socket import socket, AF_INET, SOCK_STREAM IP = "127.0.0.1" PORT = 8888 ADDRESS = (IP, PORT) BUFSIZE = 1024 print("客户端开启了") # 1.创建客户端socket对象 cliSocket = socket(AF_INET, SOCK_STREAM) # 2.连接服务器地址 cliSocket.connect(ADDRESS) print(cliSocket) # 3.收发数据 cliSocket.send("客户端发送的数据".encode("utf-8")) data = cliSocket.recv(BUFSIZE) print(data.decode("utf-8")) # 4.关闭客户端 cliSocket.close() print("客户端关闭了")
焚膏油以继晷,恒兀兀以穷年。