先来想个问题,不同电脑上的进程之间如何通信?
首先通过ip地址找到网络中对应的电脑,然后通过传输协议和端口号来确定这个进程(运行起来的软件),那么数据如何传输需要使用socket来完成,也就是进程之间通信使用socket。
运行的程序或者软件称之为进程,所谓进程间通信是指运行程序之间的数据共享。
所谓的网络编程,就是让在不同的电脑上的软件能够进行数据传递,即进程之间的通信。
1.网络传输方式
网络通信中根据数据发送方法进行分类,主要分为以下两种
- 面向无连接型
- 面向有连接型
2.socket
socket(套接字)是进程间通信的一个工具,它能实现把数据从A传输到B,完成不同主机上进程之间的通信,通俗讲socket就是完成不同电脑上进程之间通信的一个工具,负责运输进程之间的数据。
3.UDP
UDP(User Datagram Protocol)简称用户数据报协议,它是无连接的、不可靠的网络传输协议。udp属于传输层。udp网络传输协议就相当于现实生活中的写信。
udp特点:
- 无连接
- 资源开销小
- 传输速度快
- 传输数据量小,每个数据包最大是64K
udp优点:
- 传输速度快
- 不需要连接,资源开销小
udp缺点:
- 传输数据不可靠,容易丢失数据包
- 没有流量控制
udp的使用场景:
- 视频、音频等多媒体通信(即时通信)
- 包总量较少的通信(DNS)
- 限定于LAN等特定网络中的应用通信
UDP是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
UDP不严格区分客户端与服务器。
创建一个基于udp的网络程序流程步骤:
- 创建客户端套接字
- 发送/接收数据
- 关闭套接字
案例一 udp发送广播消息
import socket
if __name__ == '__main__':
# 创建udp的套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 默认udp套接字是不能发送广播消息的,需要开启广播选项
# 1. SOL_SOCKET表示当前套接字
# 2. SO_BROADCAST 表示广播选项
# 3. True表示开启广播选项
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, True)
send_data = "大家好,我是与二月!".encode("gbk")
# 发送数据
# 192.168.131.255, 局域网的广播地址
# 255.255.255.255 通用的广播地址
udp_socket.sendto(send_data, ("192.168.131.255", 9090))
# 关闭套接字
udp_socket.close()
案例二 udp聊天器(单任务版)
import socket
# 显示功能菜单
def show_menu():
# 显示程序的功能菜单
print("-----------udp聊天器0.9------------")
print("0. 退出")
print("1. 发送数据")
print("2. 接收数据")
print("---------------------------------------")
# 发送数据
def send_msg(current_udp_socket):
# 接收用户输入的数据
send_content = input("请输入您要发送的内容:")
# 对数据进行编码
send_data = send_content.encode("gbk")
# 发送数据
current_udp_socket.sendto(send_data, ("192.168.42.62", 8080))
# 接收数据
def recv_msg(current_udp_socket):
# 接收数据, 代码执行到recvfrom 会阻塞,直到收到对方的数据以后代码再继续往下执行
# 接收到的数据是一个元组
# 第1个元素是对方发送的数据
# 第2个元素是对方的ip和端口
recv_data, ip_port = current_udp_socket.recvfrom(1024)
# 对二进制数据进行解码
recv_content = recv_data.decode("gbk")
print("接收到的数据为:", recv_content, ip_port)
if __name__ == '__main__':
# 创建udp的套接字
udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# 给udp绑定端口号 ip地址和端口号以元组形式传递给bind(),ip一般不用写,表示本机的任何一个ip
udp_socket.bind(("",9090))
while True:
show_menu()
menu_option = input("请输入功能选项:")
if menu_option == "1":
send_msg(udp_socket)
elif menu_option == "2":
recv_msg(udp_socket)
elif menu_option == "0":
break
# 关闭套接字
udp_socket.close()