Python 网络编程

   日期:2020-09-08     浏览:95    评论:0    
核心提示:作者:billy版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处网络基础TCP 编程UDP 编程

作者:billy
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

网络基础

计算机为了联网,就必须规定通信协议,所谓通信协议就是计算机在网络中进行数据交换而建立的规则、标准或约定的集合。早期的计算机网络都是由各厂商自己规定一套协议,IBM、Apple 和 Microsoft 都有各自的网络协议,互不兼容。这就好比一群人,有的说中文,有的说英文,有的说德文,说同一种语言的人可以交流,不同语言之间就无法交流。

为了把全世界的所有不同类型的计算机都连接起来,就必须规定一套全球通用的协议,为了实现互联网这个目的,互联网协议(Internet Protocol Suite)诞生了。由于全世界的计算机众多,网络节点纷繁复杂,要想将数以亿计的网络设备都连通在一起,就需要进行分层。这也是将复杂的问题进行分解的一种思想。

因此互联网的实现,是按分层构建的。每一层都有自己独特的功能,而且上层的实现需要依赖于下层的功能。这就像建筑物一样,每一层都靠下一层支持。一般互联网的协议有 OSI 七层模型,和 TCP/IP 协议,如下图所示:

协议和套接字

  1. IP 协议
    在通信时,通信双方必须知道对方的标识,好比发送快递必须知道对方的地址。互联网上每个计算机的唯一标识就是 IP 地址。IP 地址实际上是一个 32 位整数(称为 IPv4),以字符串表示的 IP 地址如 172.16.254.1 实际上是把 32 位整数按 8 位分组后的数字表示,目的是便于阅读。
    IP 协议负责把数据从一台计算机通过网络发送到另一台计算机。数据被分割成一小块一小块,类似于将一个大包裹拆分成几个小包裹,然后通过 IP 包发送出去。由于互联网链路复杂,两台计算机之间经常有多条线路,因此,路由器就负责决定如何把一个 IP 包转发出去。IP 包的特点是按块发送,途径多个路由,但不保证都能到达,也不保证顺序到达。

  2. TCP 协议
    TCP 协议是建立在 IP 协议之上的。TCP 协议负责在两台计算机之间建立可靠连接,保证数据包按顺序到达。TCP 协议会通过 3 次握手建立可靠连接,然后对每个 IP 包编号,确保对方按顺序收到,如果包丢掉了,就自动重发。
    许多常用的更高级的协议都是建立在 TCP 协议基础上的,比如用于浏览器的 HTTP 协议、发送邮件的 SMTP 协议等。一个 TCP 报文除了包含要传输的数据外,还包含源 IP 地址和目标 IP 地址,源端口和目标端口。

  3. UDP 协议
    相对于 TCP 协议,UDP 协议则是面向无连接的协议。使用 UDP 协议时,不需要建立连接,只需要知道对方的 IP 地址和端口号,就可以直接发送数据包。但是,数据无法保证一定到达。虽然用 UDP 传输数据不可靠,但它的优点是比 TCP 协议速度快。对于不要求可靠到达的数据,就可以使用 UDP 协议。

  4. 套接字 Socket
    为了让两个程序通过网络进行通信,二者均必须使用 Socket 套接字。Socket 的英文原意是 “孔” 或 “插座”,通常也称作 “套接字”,用于描述 IP 地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。
    Socket 正如其英文原意那样,像一个多孔插座。一台主机犹如布满各种插座的房间,每个插座有一个编号,有的插座提供 220 伏交流电,有的提供 110 伏交流电,有的则提供有线电视节目。客户软件将插头插到不同编号的插座,就可以得到不同的服务。

在 Python 中使用 socket 模块的函数 socket() 来创建套接字,语法如下:
s = socket.socket(AddressFamily, Type)

  • Address Family:可以选择 AF_INET(用于 Internet 进程间通信)或者 AF_UNIX(用于同一台机器进程间通信),实际工作中常用 AF_INET;
  • Type:套接字类型,可以是 SOCK_STREAM(流式套接字,主要用于 TCP 协议)或者 SOCK_DGRAM(数据报套接字,主要用于 UDP 协议);

Socket 对象的内置方法如下表所示:

函数 描述
s.bind() 绑定地址(host, port)到套接字,在 AF_INET 下以元组 (host, port) 的形式表示地址
s.listen() 开始 TCP 监听。backlog 指定在拒绝连接之前,操作系统可以挂起的最大连接数量。该值至少为 1,大部分应用程序设为 5 就可以了
s.accept() 被动接收 TCP 客户端连接,并且以阻塞方式等待连接的到来
s.connect() 主动初始化 TCP 服务器连接,一般 address 的格式为元组 (host, port),如果连接出错,则返回 socket.error 错误
s.recv() 接收 TCP 数据,数据以字符串形式返回,bufsize 指定要接受的最大数据量。flag 提供有关消息的其他信息,通常可以忽略
s.send() 发送 TCP 数据,将 string 中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于 string 的字节大小
s.sendall() 完整发送 TCP 数据。将 string 中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回 None,失败则抛出异常
s.recvfrom() 接收 UDP 数据,与 recv() 类似,但返回值是 (data, address)。其中 data 是包含接收数据的字符串,address 是发送数据的套接字地址
s.sendto() 发送 UDP 数据,将数据发送到套接字,address 是形式为 (ipaddr, port) 的元组,指定远程地址。返回值是发送的字节数
s.close() 关闭套接字

TCP 编程

由于 TCP 连接具有安全可靠的特性,所以 TCP 应用更为广泛。创建 TCP 连接时,主动发起连接的叫客户端,被动响应连接的叫服务器。TCP 客户端和服务器通信模型如下图所示:

示例:

# server.py
import socket

host = socket.gethostname()                         	# 获取主机地址
port = 12345                                       	# 设置端口号
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)	# 创建 TCP/IP 套接字
s.bind((host, port))                            	# 绑定地址 (host, port) 到套接字
s.listen(1)                         			# 设置最多连接数量
print("开始监听,等待客户端连接...")
sock, addr = s.accept()                            	# 被动接收 TCP 客户端连接
print("连接已建立")

info = sock.recv(1024).decode()            		# 接收客户端数据
while info != 'byebye':
    if info:
        print("从客户端接收到的内容是: " + info)
    send_data = input("输入要发送的内容: ")         	# 发送消息
    sock.send(send_data.encode())                	# 发送 TCP 数据
    if send_data == 'byebye':                   	# 如果发送 byebye,则退出
        break;
    info = sock.recv(1024).decode()             	# 接收客户端数据

sock.close()                                       	# 关闭客户端套接字
s.close()                                         	# 关闭服务器套接字
# client.py
import socket

s = socket.socket()
host = socket.gethostname()
port = 12345
s.connect((host, port))
print("已连接服务器")

info = ''
while info != 'byebye':
    send_data = input("请输入要发送的内容: ")
    s.send(send_data.encode())
    if send_data == 'byebye':
        break;
    info = s.recv(1024).decode()
    print("接收到的内容是: " + info)
s.close()

上述例子的运行结果为:

# server.py
开始监听,等待客户端连接...
连接已建立
从客户端接收到的内容是: 123456
输入要发送的内容: 987555
# client.py
已连接服务器
请输入要发送的内容: 123456
接收到的内容是: 987555
请输入要发送的内容: byebye

UDP 编程

UDP 是面向消息的协议,通信时不需要建立连接,数据的传输自然是不可靠的,UDP 一般用于多点通信和实时的数据业务,例如:

  • 语音广播
  • 视频
  • 聊天软件
  • TFTP(简单文件传送)
  • SNMP(简单网络管理协议)
  • RIP(路由信息协议,如报告股票市场、航空信息)
  • DNS(域名解释)

和 TCP 类似,使用 UDP 的通信双方也分为客户端和服务器,UDP 通信模型如下图所示:

示例:

# server.py
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    # 创建 UDP 套接字
s.bind(("127.0.0.1", 8888))   				# 绑定地址 (host, port) 到套接字
print("绑定 UDP 到 8888 端口")

data, addr = s.recvfrom(1024)   			# 接收数据,返回值是 (data, address)。其中 data 是包含接收数据的字符串,address 是发送数据的套接字地址
data = float(data) * 1.8 + 32   			# 转化公式
send_data = "转换后的温度(单位:华氏温度): " + str(data)
print("Received from %s: %s" % addr)
s.sendto(send_data.encode(), addr)  			# 发送给客户端
s.close()       					# 关闭服务器套接字
# client.py
import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)    # 创建 UDP 套接字
data = input("请输入要转换的温度(单位:摄氏度): ")	# 输入要转换的温度
s.sendto(data.encode(), ("127.0.0.1", 8888))		# 发送数据
print(s.recv(1024).decode())				# 打印接收数据
s.close()						# 关闭套接字

上述例子的运行结果为:

# server.py
绑定 UDP 到 8888 端口
Received from 127.0.0.1: 59470
# client.py
请输入要转换的温度(单位:摄氏度): 25
转换后的温度(单位:华氏温度): 77.0

更多请参考

  • Python 进阶之路
 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服