自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm=1001.2014.3001.5501
当今的时代是一个网络的时代,网络无处不在。而我们前面学习编写的程序都是单机的,即不能和其他电脑上的程序进行通信。为了实现不同电脑之间的通信,就需要使用网络编程。下面,我们来了解一下网络相关的基础知识。
1 为什么要使用通信协议
计算机为了联网,就必须规定通信协议,早期的计算机网络,都是由各厂商自己规定一套协议,IBM、Apple和Microsoft都有各自的网络协议,互不兼容,这就好比一群人有的说英语,有的说中文,有的说德语,说同一种语言的人可以交流,不同的语言之间就不行了,如图1所示。
图1 语言不通,无法交流
为了把全世界的所有不同类型的计算机都连接起来,就必须规定一套全球通用的协议,为了实现互联网这个目标,互联网协议簇(Internet Protocol Suite)即通用协议标准出现了。Internet是由inter和net两个单词组合起来的,原意就是连接“网络”的网络,有了Internet,任何私有网络,只要支持这个协议,就可以接入互联网。
2 TCP/IP简介
因为互联网协议包含了上百种协议标准,但是最重要的两个协议是TCP和IP协议,所以,大家把互联网的协议简称TCP/IP协议。
(1)IP协议
在通信时,通信双方必须知道对方的标识,好比发送快递必须知道对方的地址。互联网上每个计算机的唯一标识就是IP地址。IP地址实际上是一个32位整数(称为IPv4),它是以字符串表示的IP地址,如172.16.254.1,实际上是把32位整数按8位分组后的数字表示,目的是便于阅读,如图2所示。
图2 IPv4示例
IP协议负责把数据从一台计算机通过网络发送到另一台计算机。数据被分割成一小块一小块,类似于将一个大包裹拆分成几个小包裹,然后通过IP包发送出去。由于互联网链路复杂,两台计算机之间经常有多条线路,因此,路由器就负责决定如何把一个IP包转发出去。IP包的特点是按块发送,途经多个路由,但不保证都能到达,也不能保证顺序到达。
(2)TCP协议
TCP协议则是建立在IP协议之上的。TCP协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP协议会通过3次握手建立可靠连接,如图3所示。
图3 TCP的三次握手
然后需要对每个IP包进行编号,确保对方按顺序收到,如果包丢掉了,就自动重发。如图4所示。
图4 传输数据包
许多常用的更高级的协议都是建立在TCP协议基础上的,比如用于浏览器的HTTP协议、发送邮件的SMTP协议等。一个TCP报文除了包含要传输的数据外,还包含源IP地址和目标IP地址、源端口和目标端口。
端口有什么作用?在两台计算机通信时,只发送IP地址是不够的,因为同一台计算机上运行着多个网络程序。一个TCP报文来了之后,到底是交给浏览器还是QQ,就需要端口号来区分。每个网络程序都向操作系统申请唯一的端口号,这样,两个进程在两台计算机之间建立网络连接就需要各自的IP地址和各自的端口号。
一个进程也可能同时与多个计算机建立链接,因此它会申请很多端口。端口号不是随意使用的,而是按照一定的规定进行分配。例如,80端口分配给HTTP服务,21端口分配给FTP服务。
3 UDP简介
相对TCP协议,UDP协议则是面向无连接的协议。使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,数据无法保证一定到达。虽然用UDP传输数据不可靠,但它的优点是比TCP协议的速度快。对于不要求可靠到达的数据而言,就可以使用UDP协议。TCP协议和UDP协议的区别如图5所示。
图5 TCP协议和UDP协议的区别
4 Socket简介
为了让两个程序通过网络进行通信,二者均必须使用Socket套接字。Socket的英文原义是“孔”或“插座”,通常也称作“套接字”,用于描述IP地址和端口,它是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信,如图6所示。在Internet上的主机上一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
图6 使用Socket实现通信
Socket正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供220伏交流电,有的提供110伏交流电,有的则提供有线电视节目。客户软件将插头插到不同编号的插座,就可以得到不同的服务。
在Python中使用socket 模块的 socket()函数就可以完成,语法格式如下:
s = socket.socket(AddressFamily, Type)
函数socket.socket创建一个socket,返回该socket的描述符,该函数带有两个参数:
l Address Family:可以选择 AF_INET(用于Internet进程间通信) 或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用AF_INET。
l Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议)。
例如,为了创建 TCP/IP 套接字,可以用下面的方式调用socket.socket():
tcpSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
同样,为了创建 UDP/IP 套接字,需要执行以下语句:
udpSock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
创建完成后,生成一个socket对象,socket对象的主要方法如表1所示。
表1 socket对象的内置方法
函 数 | 描 述 |
s.bind() | 绑定地址(host,port)到套接字, 在AF_INET下,以元组(host,port)的形式表示地址 |
s.listen() | 开始TCP监听。backlog指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为1,大部分应用程序设为5就可以了 |
s.accept() | 被动接受TCP客户端连接(阻塞式),等待连接的到来 |
s.connect() | 主动初始化TCP服务器连接,一般address的格式为元组(hostname,port),如果连接出错,返回socket.error错误 |
s.recv() | 接收TCP数据,数据以字符串形式返回,bufsize指定要接收的最大数据量。flag提供有关消息的其他信息,通常可以忽略 |
s.send() | 发送TCP数据,将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小 |
s.sendall() | 完整发送TCP数据,完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常 |
s.recvfrom() | 接收UDP数据,与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址 |
s.sendto() | 发送UDP数据,将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数 |
s.close() | 关闭套接字 |