一、网络
1、网络介绍
1.概念:
将具有独立功能的多台计算机通过通信线路和通信设备连接起来,在网络管理软件及网络通信协议下,实现资源共享和信息传递的虚拟平台。
2.学习目的
能够编写基于网络通信的软件或程序,通常来说就是网络编程。
3.要点
网络就是实现资源共享和信息传递的虚拟平台,我们可以编写基于网络通信的程序,比如:后续学习的socket编程、web开发等等。
2、IP地址介绍
1.概念
IP地址是分配给网络设备上网使用的数字标签,它能够标识网络中唯一的一台设备,好比现实中每个人都有一个手机号。
2.表现形式
有两种表现形式:ipv4 点分十进制
ipv6 冒号十六进制
3.作用
通过IP地址找到网络中唯一一台设备,然后可以跟这个设备进行数据通信。
3、ifconfig和ping命令
1.ifconfig命令
查看IP地址命令(ens33)
ipconfig:windows系统查IP地址
2.ping命令
ping IP地址 查看网络是否正常(lo)
4、端口和端口号
1.端口的概念
端口是数据传输的通道,每个端口都有一个端口号
2.端口号
操作系统为了统一管理这么多端口而设置的号码,这就是端口号,端口号其实就是一个数字,好比我们现实生活中的门牌号。
范围 0~65535
3.通信流程
通过ip地址找到对应的设备,通过端口号找到对应的端口,然后通过端口把数据给应用程序
4.分类
-
知名端口号
知名端口号是指众所周知的端口号,范围从0到1023,这些端口号一般固定分配给一些服务,比如21端口分配给FTP(文件传输协议)服务,25端口分配给SMTP(简单邮件传输协议)服务,80端口分配给HTTP服务。
-
动态端口号
一般程序员开发应用程序使用端口号称为动态端口号。
范围从1024到65535
5、socket介绍
1.概念
socket(套接字)是程序之间进行网络通信的工具
2.作用
程序之间网络数据的传输可以通过socket来完成,socket就是程序间网络数据通信的工具。
6、TCP介绍
1、概念
在网络中数据不能随便发送,在发送之前要选择网络传输方式(传输协议)
TCP简称传输控制协议,它是一种面向连接的、可靠的、基于字节流的传输层通信协议
2、通信步骤
创建连接 >>>传输数据>>>关闭连接
3、特点
-
面向连接
通信双方必须先建立好连接才能进行数据的传输,并且双方都会为此连接分配必要资源用来记录连接的状态和信息。当数据传输完成后,双方必须断开此连接,以释放系统资源。
-
可靠传输
- TCP采用发送应答机制
通过TCP这种方式发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传送成功 - 超时重传
发送端发送一个报文之后就会启动定时器,如果指定时间内没有得到应答就会重新发送这个报文段 - 错误校验
TCP用一个校验和函数来校验数据是否有错误,在发送和接收时都要计算校验和 - 流量控制和阻塞管理
流量控制用来避免发送端发送过快而使得接收方来不及接收
- TCP采用发送应答机制
二、TCP 网络应用程序开发
1、编码转换
-
encode 将字符串转化为字节码
-
decode 将字节码转化为字符串
2、TCP客户端程序开发
- 创建客户端套接字对象
- 和服务端套接字建立连接
- 发送数据
- 接收数据
- 关闭客户端套接字
import socket
if __name__ == "__main__"v
# 1. 创建客户端套接字对象 AF_INET表示ipv4网址,SOCK_STREAM表示TCP协议
tcp_client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 2. 和服务端套接字建立连接
tcp_client_socket.connect(("192.168.209.130", 8080))
# 3. 发送数据
tcp_client_socket.send("nihao".encode(encoding="utf-8"))
# 4. 接收数据 recv阻塞等待数据的接收
recv_data = tcp_client_socket.recv(1024)
print(recv_data.decode())
# 5. 关闭客户端套接字
tcp_client_socket.close()
3、TCP服务端程序开发
- 创建服务端套接字对象
- 绑定IP地址和端口号
- 设置监听(转换为被动套接字)
- 等待接收客户端连接请求
- 接收数据
- 发送数据
- 关闭套接字
import socket
if __name__ == '__main__':
# 1. 创建服务端套接字对象
tcp_serve_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_serve_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 2. 绑定IP地址和端口号
tcp_serve_socket.bind(("", 8888))
# 3. 设置监听(转换为被动状态)
tcp_serve_socket.listen(128)
# 4. 等待接收客户端连接请求 accpet阻塞等待
con_socket, ip_port = tcp_serve_socket.accept()
# 5. 接收数据
recv_data = con_socket.recv(1024)
print(recv_data.decode())
# 6. 发送数据
con_socket.send("收到".encode())
# 7. 关闭套接字
con_socket.close()
tcp_serve_socket.close()
-
补充:端口复用
当进行TCP网络应用程序开发时,端口释放不是即时的,所以要设置端口复用来释放端口
tcp_serve_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
4、注意点
-
当TCP客户端程序想要和TCP服务端程序进行通信的时候必须要先建立连接
-
TCP客户端程序一般不需要绑定端口号,因为客户端是主动发起建立连接的。
-
TCP服务端程序必须绑定端口号,否则客户端找不到这个TCP服务端程序。
-
listen后的套接字是被动套接字,只负责接收新的客户端的连接请求,不能收发消息。
-
当TCP客户端程序和TCP服务端程序连接成功后, TCP服务器端程序会产生一个新的套接字,收发客户端消息使用该套接字。
-
关闭accept返回的套接字意味着和这个客户端已经通信完毕。
-
当客户端的套接字调用close后,服务器端的recv会解阻塞,返回的数据长度为0,服务端可以通过返回数据的长度来判断客户端是否已经下线,反之服务端关闭套接字,客户端的recv也会解阻塞,返回的数据长度也为0。
5、socket的send和recv的原理
1.TCP socket的发送和接收缓冲区
当创建一个TCP socket对象时会有一个发送缓存区和接收缓存区
2.send原理刨析
要想发数据,必须得通过网卡发送数据,应用程序是无法直接通过网卡发送数据的,它需要调用操作系统接口,也就是说,应用程序把发送的数据先写入到发送缓冲区(内存中的一片空间),再由操作系统控制网卡把发送缓冲区的数据发送给服务端网卡。
3.recv原理刨析
应用软件是无法直接通过网卡接收数据的,它需要调用操作系统接口,由操作系统通过网卡接收数据,把接收的数据写入到接收缓冲区(内存中的一片空间),应用程序再从接收缓存区获取客户端发送的数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8OyPvu0f-1604711492777)(C:\Users\lzq\AppData\Roaming\Typora\typora-user-images\image-20200901101802215.png)]
4.小结
不管是recv还是send都不是直接接收到对方的数据和发送数据到对方,发送数据会写入到发送缓冲区,接收数据是从接收缓冲区来读取,发送数据和接收数据最终是由操作系统控制网卡来完成。
6.TCP服务端开发-多任务版
import socket
import threading
def send_recv(con_socket):
# 5. 接收数据
recv_data = con_socket.recv(1024)
print(recv_data.decode())
# 6. 发送数据
con_socket.send("收到".encode())
# 7. 关闭套接字
con_socket.close()
if __name__ == '__main__':
# 1. 创建服务端套接字对象
tcp_serve_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcp_serve_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 2. 绑定IP地址和端口号
tcp_serve_socket.bind(("", 8888))
# 3. 设置监听(转换为被动状态)
tcp_serve_socket.listen(128)
# 4. 等待接收客户端连接请求 accpet阻塞等待
while True:
con_socket, ip_port = tcp_serve_socket.accept()
t = threading.Thread(target=send_recv, args=(con_socket,))
t.start()
tcp_serve_socket.close()
补充
1、三次握手和四次挥手
1)三次握手
- 第一次握手:客户端发送TCP报文;其中将标记位SYN置1,表示“请求建立新连接;报文序号seq = x(一般为1);随后客户端进入SYN-SENT阶段。【客户端发送来连接请求】
- 第二次握手:服务端接收到客户端的报文后结束listen,并发送一份TCP报文;其中标记位为SYN和ACK,表示"确认客户端报文seq序号有效,服务器收到数据,并同意创建新连接";报文序号seq = y(一般为1);确认号为ack = x + 1(将客户端的报文序号加一作为确认号);服务端进入SYN-RCVD阶段。【服务端回复收到请求,同时向客户端发送同意连接的信息】
- 第三次握手:客户端收到服务器TCP报文,确定数据传输正常,结束SYN-SENT阶段;并返回最后TCP报文,其中标志位ACK,表示"确认收到服务器同意连接的信号"‘;报文序号seq = x + 1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;随后客户端进入ESTABLISHED阶段。【客户端回复收到服务器同意连接的信息】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iMSeU3Vs-1604711492779)(C:\Users\lzq\AppData\Roaming\Typora\typora-user-images\image-20200901195811057.png)]
2)四次挥手
- 第一次挥手:主机1(可以是客户端,也可以是服务器端),设置
Seq
和Ack
,向主机2发送一个FIN
报文段;此时,主机1进入FIN_WAIT_1
状态;这表示主机1没有数据要发送给主机2了;【客户端发送断开连接请求】 - 第二次挥手:主机2收到了主机1发送的
FIN
报文段,向主机1回一个ACK
报文段,Ack为
Seq加1;主机1进入FIN_WAIT_2
状态;主机2告诉主机1,我也没有数据要发送了,可以进行关闭连接了;【服务器收到客户端的请求并回复收到,客户端单向断开连接】 - 第三次挥手:主机2向主机1发送
FIN
报文段,请求关闭连接,同时主机2进入CLOSE_WAIT
状态;【当数据全部传输完成后,服务器向客户端发送断开连接请求】 - 第四次挥手:主机1收到主机2发送的
FIN
报文段,向主机2发送ACK
报文段,然后主机1进入TIME_WAIT
状态;主机2收到主机1的ACK
报文段以后,就关闭连接;此时,主机1等待2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,主机1也可以关闭连接了。【客户端向服务器回复同意请求以让服务器断开连接,同时客户端会等待MSL来确保服务端收到信息】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3UoRNBMT-1604711492780)(C:\Users\lzq\AppData\Roaming\Typora\typora-user-images\image-20200901195655334.png)]
2、os模块
1)文件查询
os.lisdir()
# [文件1, 文件2, ......]
os.path.getsize()
# 获取指定文件大小
os.path.exists()
# 判断指定文件是否存在
收到回复,则证明Server端已正常关闭**,那好,主机1也可以关闭连接了。【客户端向服务器回复同意请求以让服务器断开连接,同时客户端会等待MSL来确保服务端收到信息】
[外链图片转存中…(img-3UoRNBMT-1604711492780)]
2、os模块
1)文件查询
os.lisdir()
# [文件1, 文件2, ......]
os.path.getsize()
# 获取指定文件大小
os.path.exists()
# 判断指定文件是否存在