Python高级语法——网络编程——进阶学习笔记
项目中案例参考:
https://github.com/FangbaiZhang/Python_advanced_learning/tree/master/03_Python_network_programming
1 网络通信
- 使用网络能够把多方链接在一起,然后可以进行数据传递
- 所谓的网络编程就是,让在不同的电脑上的软件能够进行数据传递,即进程之间的通信
1.1 UDP
-
UDP简介:
Internet 协议集支持一个无连接的传输协议,
该协议称为用户数据报协议(UDP,User Datagram Protocol)。
UDP 为应用程序提供了一种无需建立连接就可以发送封装的 IP 数据报的方法。UDP协议与TCP协议一样用于处理数据包,在OSI模型中,两者都位于传输层,
处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,
也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP协议类似生活中的写信和广播,不用创建连接,直接发送出去,不管对方收到没
1.2 TCP
-
TCP简介:
传输控制协议(TCP,Transmission Control Protocol)
是一种面向连接的、可靠的、基于字节流的传输层通信协议TCP通信需要经过创建连接、数据传送、终止连接三个步骤。
TCP通信模型中,在通信开始之前,一定要先建立相关的链接,
才能发送数据,类似于生活中,“打电话”" -
TCP特点:
-
面向连接
通信双方必须先建立连接才能进行数据的传输,
双方都必须为该连接分配必要的系统内核资源,
以管理连接的状态和连接上的传输。
双方间的数据传输都可以通过这一个连接进行。
完成数据交换后,双方必须断开此连接,以释放系统资源。
这种连接是一对一的,因此TCP不适用于广播的应用程序,
基于广播的应用程序请使用UDP协议。 -
可靠传输
1)TCP采用发送应答机制
TCP发送的每个报文段都必须得到接收方的应答才认为这个TCP报文段传输成功
2)超时重传
发送端发出一个报文段之后就启动定时器,如果在定时时间内没有收到应答就重新发送这个报文段。
TCP为了保证不发生丢包,就给每个包一个序号,同时序号也保证了传送到接收端实体的包的按序接收。
然后接收端实体对已成功收到的包发回一个相应的确认(ACK);
如果发送端实体在合理的往返时延(RTT)内未收到确认,
那么对应的数据包就被假设为已丢失将会被进行重传。
3)错误校验
TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
- 流量控制和阻塞管理
流量控制用来避免主机发送得过快而使接收方来不及完全收下。
-
1.3 TCP与UDP区别
-
TCP和UDP的区别
TCP面向连接(read/write/send/recv),而UDP无连接(sendto,recvfrom)
TCP是可靠传输(超时重传+数据应答),UDP不可靠
TCP是点对点连接,UDP可以一对多的
TCP面向字节流,UDP面向数据报
TCP给HTTP,HTTPS,FTP,TELNET,SMTP等使用,UDP给DNS,DHCP,NFS,IGMP,TFTP等
TCP严格区分客户端和服务器
UDP不用严格区分,比如37_1_UDP服务器端和客户端:
37_2_UDP客户端是分开的,001/002_UDP聊天器案例就是一个程序 -
TCP比UDP的优势:安全稳定
面向连接(确认有创建三方交握,连接已创建才作传输。)
有序数据传输
重发丢失的数据包
舍弃重复的数据包
无差错的数据传输
阻塞/流量控制 -
UDP类似写信:写信,一定需要地址,但是写信不安全,即UDP发送的消息可能会丢失,不安全,不创建连接,不管对方收到没,发出去就行了
-
TCP类似打电话:必须先接通电话,创建连接,安全的,点对点,信号不好再说一遍(超时重传+数据应答)
-
讲这么多:记住:TCP比UDP安全稳定可靠,现在网络通信绝大多数都是使用的TCP/IP协议
2 IP地址
2.1 IP地址查看
- 方法1:直接打开网络,查看属性
- 方法2:命令窗口查看,Linux使用ifconfig查看
- windows+R打开CMD窗口
- ipconfig查看IP地址相关信息
- 无线局域网适配器 WLAN:
连接特定的 DNS 后缀 . . . . . . . :
IPv6 地址 . . . . . . . . . . . . : 2409:8962:804:2874:28fb:6bc4:bfa6:7c83
临时 IPv6 地址. . . . . . . . . . : 2409:8962:804:2874:c8bc:e87e:19d1:8130
本地链接 IPv6 地址. . . . . . . . : fe80::28fb:6bc4:bfa6:7c83%19
IPv4 地址 . . . . . . . . . . . . : 192.168.43.143
子网掩码 . . . . . . . . . . . . : 255.255.255.0
默认网关. . . . . . . . . . . . . : fe80::9687:e0ff:fe11:ecc4%19
192.168.43.1
2.2 IP地址分类
-
IPv4: 192.168.43.143
IP代表具体的地址,v4代表第四个版本
xxx.xxx.xxx.xxx xxx是1-256的数字组合 256256256*256个地址,现在已经枯竭了
每个国家有自己的IP区域,每个省份地区都有对应的IP区域 -
IPv5: 研究阶段死掉了
-
IPv6: fe80::28fb:6bc4:bfa6:7c83%19
-
IPv4: xxx.xxx.xxx.xxx
四组数字,但是包括两部分:网络地址(网络号)和主机地址(主机号)
比如:
192.168.43. 同一个局域网,前三组当做网络号
143 最后一组当做主机号,同一个局域网,不同电脑网络号不同 -
IPv4地址分类:A/B/C/D/E五类,我们局域网一般用的是C类,参考图片002
-
在这么多网络IP中,国际规定有一部分IP地址是用于我们的局域网使用,
也就是属于私网IP,不在公网中使用的,
所以家里网络地址都是192.168.xxx.xxx,它们的范围是:
10.0.0.0~10.255.255.255
172.16.0.0~172.31.255.255
192.168.0.0~192.168.255.255 -
IP地址127.0.0.1~127.255.255.255用于回路测试
127.0.0.1可以代表本机IP地址
3 端口
-
端口是什么?举个栗子
- 上面通过IP地址可以定位到一台网络中的唯一电脑,但是电脑上有很多程序,
- 比如聊天的QQ,微信,飞行等,对方发来消息该谁接收,此时就需要端口,
- 每个程序服务都有自己的端口
-
端口号
端口是通过端口号来标记的,端口号只有整数,范围是从0到65535端口号不是随意使用的,而是按照一定的规定进行分配。
端口的分类标准有好几种,我们这里不做详细讲解,只介绍一下知名端口和动态端口 -
知名端口(Well Known Ports)
知名端口是众所周知的端口号,范围从0到1023
80端口分配给HTTP服务
21端口分配给FTP服务- 类似于特殊电话号码110 119 10086
-
动态端口(Dynamic Ports)
动态端口的范围是从1024到65535
之所以称为动态端口,是因为它一般不固定分配某种服务,而是动态分配。
动态分配是指当一个系统程序或应用程序程序需要网络通信时,
它向主机申请一个端口,主机从可用的端口号中分配一个供它使用。
当这个程序关闭时,同时也就释放了所占用的端口号 -
端口有什么用呢 ?
我们知道,一台拥有IP地址的主机可以提供许多服务,
比如HTTP(万维网服务)、FTP(文件传输)、SMTP(电子邮件)等,
这些服务完全可以通过1个IP地址来实现。
那么,主机是怎样区分不同的网络服务呢?
显然不能只靠IP地址,因为IP地址与网络服务的关系是一对多的关系。
实际上是通过“IP地址+端口号”来区分不同的服务的。
需要注意的是,端口并不是一一对应的。
比如你的电脑作为客户机访问一台WWW服务器时,
WWW服务器使用“80”端口与你的电脑通信,
但你的电脑则可能使用“3457”这样的端口。
4 socket编程(套接字)
-
SOCKET编程(来自TLXY)
- 套接字
- 一个网络通信的端点,能实现不同主机的进程通信
- 通过IP和端口定位对方发送消息的通信机制
- 分为UDP和TCP两种协议方式
- UDP协议用于即时通讯,要求速度快,内容少
- TCP协议,传输控制协议(英语:Transmission Control Protocol)
- TCP是一种面向连接的、可靠的、基于字节流的传输层通信协议
- 客户端Client: 发起访问的一方
- 服务器端Server:接受访问的一方
-
不同电脑上的进程如何进行通信(比如两个QQ):
在1台电脑上可以通过进程号(PID)来唯一标识一个进程,但是在网络中这是行不通的。
其实TCP/IP协议族已经帮我们解决了这个问题,网络层的“ip地址”可以唯一标识网络中的主机,
而传输层的“协议+端口”可以唯一标识主机中的应用进程(进程)。
这样利用ip地址,协议,端口就可以标识网络的进程了,
网络中的进程通信就可以利用这个标志与其它进程进行交互
注意:
所谓进程指的是:运行的程序以及运行时用到的资源这个整体称之为进程
所谓进程间通信指的是:运行的程序之间的数据共享 -
socket(简称套接字) 是进程间通信的一种方式,它与其他进程间通信的一个主要不同是:
它能实现不同主机间的进程间通信,我们网络上各种各样的服务大多都是基于 Socket 来完成通信的 -
在 Python中使用socket模块的函数socket就可以完成
import socket
socket.socket(AddressFamily, Type)函数 socket.socket 创建一个socket对象,该函数带有两个参数:
Address Family:可以选择AF_INET(用于 Internet 进程间通信)或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET
Type:套接字类型,可以是SOCK_STREAM(流式套接字,主要用于TCP协议)或者SOCK_DGRAM(数据报套接字,主要用于UDP协议) -
使用socket流程:
套接字使用流程与文件的使用流程很类似
创建套接字
使用套接字收/发数据
关闭套接字 -
socket套接字实例:UDP套接字,查看004文件中案例
服务器端:37_1_UDP服务器端
客户端:37_2_UDP客户端- 本地聊天发送消息和接收消息可以集成在一个程序中
- 参考001/002_UDP聊天器
-
UDP绑定端口问题:
一般情况下,在一台电脑上运行的网络程序有很多,为了不与其他的网络程序占用同一个端口号,
往往在编程中,udp的端口号一般不绑定,
但是如果需要做成一个服务器端的程序的话,是需要绑定的,想想看这又是为什么呢?
如果报警电话每天都在变,想必世界就会乱了,
所以一般服务性的程序,往往需要一个固定的端口号,这就是所谓的端口绑定一个udp网络程序,可以不绑定,此时操作系统会随机进行分配一个端口,如果重新运行此程序端口可能会发生变化
一个udp网络程序,也可以绑定信息(ip地址,端口号),如果绑定成功,
那么操作系统用这个端口号来进行区别收到的网络数据是否是此进程的37案例中服务器端就是绑定了固定的端口
-
网络通信补充:
单工:只能接收数据(比如收音机)
半双工:可以接收也可以发送数据,但是不能同时进行(对讲机,只能一个人说,另外一个接收)
全双工:可以同时发送接收数据(打电话,可以同时说)
套接字是全双工的 -
UDP聊天器案例:
- 说明:
在一个电脑中编写1个程序,有2个功能
1.获取键盘数据,并将其发送给对方
2.接收数据并显示
并且可以选择以上的2个功能调用 - 参考001/002_UDP聊天器案例
- 说明:
5 TCP客户端/服务器
5.1 tcp客户端/服务器实现
-
查看002_网络_tcp文件夹中实例
-
tcp客户端
- 创建tcp的套接字对象
- 链接服务器端
- 发送数据/接收对方发送过来的数据
- 关闭tcp套接字对象
- 客户端一般不绑定固定的ip和port,因为客户端会发生变化,只是连接服务器端,自动分配端口
- 参考案例:001_TCP客户端
-
tcp服务器
- socket创建一个套接字
- bind绑定ip和port
- listen使套接字变为可以被动链接(监听套接字,等待客户请求)
- accept等待客户端的链接,返回一个新客户端
- recv/send接收发送数据
- 关闭新客户端和套接字
- 参考案例:002_TCP服务器端
服务器对比客户端多了3和4两步,监听listen和accept
类似于:
买个手机
插上手机卡
设计手机为正常接听状态(即能够响铃)
静静的等着别人拨打 -
同时运行本地的001_TCP客户端和002_TCP服务器端步骤:
- 先运行002_TCP服务器端,等待链接,阻塞状态
- 运行001_TCP客户端,链接服务器,解除服务器阻塞
- 服务器等待客户端发来数据,处于阻塞状态
- 客户端发送数据,服务器接收数据,解除阻塞
- 服务器返回数据给客户端
- 客户端接收数据
- 关闭客户端和服务器端
-
服务器端运行结果:
监听中,等待客户端链接…
客户端已链接,客户端地址:
(‘127.0.0.1’, 7110)
我是客户端!!! -
客户端运行结果:
请输入要链接的服务器的IP:127.0.0.1
请输入要链接的服务器的port:8080
请输入要发送的数据(输入EXIT退出):我是客户端!!!
请输入要发送的数据(输入EXIT退出):EXIT
接收到的数据为: 数据已收到
5.2 TCP服务器端循环为多个客户端服务
- 003_TCP服务器端循环监听
5.3 TCP文件下载
- 004/005/006_下载文件
5.4 TCP注意点
-
tcp注意点
tcp服务器一般情况下都需要绑定,否则客户端找不到这个服务器
tcp客户端一般不绑定,因为是主动链接服务器,所以只要确定好服务器的ip、port等信息就好,本地客户端可以随机
tcp服务器中通过listen可以将socket创建出来的主动套接字变为被动的,这是做tcp服务器时必须要做的
当客户端需要链接服务器时,就需要使用connect进行链接,udp是不需要链接的而是直接发送,但是tcp必须先链接,只有链接成功才能通信
当一个tcp客户端连接服务器时,服务器端会有1个新的套接字,这个套接字用来标记这个客户端,单独为这个客户端服务
listen后的套接字是被动套接字,用来接收新的客户端的链接请求的,而accept返回的新套接字是标记这个新客户端的
关闭listen后的套接字意味着被动套接字关闭了,会导致新的客户端不能够链接服务器,但是之前已经链接成功的客户端正常通信。
关闭accept返回的套接字意味着这个客户端已经服务完毕
当客户端的套接字调用close后,服务器端会recv解堵塞,并且返回的长度为0,因此服务器可以通过返回数据的长度来区别客户端是否已经下线
项目中案例参考:
https://github.com/FangbaiZhang/Python_advanced_learning/tree/master/03_Python_network_programming