TCP 就如打电话一样,要先建立连接,然后才能通信,这样可以保证我们通信的内容完整性。而 UDP 则是面向无连接的协议,使用 UDP 协议时,不需要建立连接,只需要知道对方的 IP 地址和端口号,就可以直接发数据包。但是,我们无法确保我们发的数据能不能或能不能全部到达对方。
服务器首先需要绑定端口,创建 Socket 时,SOCK_DGRAM 指定了这个 Socket 的类型是 UDP。绑定端口和 TCP 一样,但是不需要调用 listen 方法,而是直接接收来自任何客户端的数据。
''' 此为服务器端程序 ''' import socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建套接字 server_socket.bind(('127.0.0.1', 8889)) # 绑定的 IP 和端口 while True: # 接收数据: print("等待客户端发送来的数据......") client_data, server_addr = server_socket.recvfrom(1024) # 接收客户端信息 client_data = client_data.decode("utf-8") # 解码字节流 if client_data == "exit": # 判断客户端是否申请结束会话 print("服务器端退出通信") server_socket.sendto("exit".encode("utf-8"), server_addr) # 通知客户端关闭 break print(client_data) # 发送数据 server_data = input("请输入要发送给客户端的信息:") server_socket.sendto(server_data.encode("utf-8"), server_addr) # 发送信息 server_socket.close()
我们在此写个和服务器通信的客户端代码,大家先运行上面的服务器代码,然后再运行这个客户端代码,双方就可以进行数据发送了,客户端代码如下。
''' 此为客户端程序 ''' import socket client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建套接字 server_ipport = ("127.0.0.1", 8889) # 通信的服务器的 ip 和端口 while True: # 发送数据 client_data = input("请输入要发送给服务器的信息:") client_socket.sendto(client_data.encode("utf-8"), server_ipport) # 发送信息 # 接收数据 server_data, client_addr = client_socket.recvfrom(1024) # 接收服务器信息 server_data = server_data.decode("utf-8") # 解码字节流 if server_data == "exit": # 判断服务器是否申请结束会话 print("客户端退出通信") client_socket.sendto("exit".encode("utf-8"), server_ipport) # 通知服务器端关闭 break print("收到服务器信息:%s" % server_data) client_socket.close() # 关闭套接字
UDP 是有消息边界的,我们每次调用 sendto(udp 协议发送消息用的是 sendto 函数)发送一个数据包,都是一个完整的包发送到对方(当然这个包的数据有可能会有部分丢失),但是每一次的 sendto 发送的数据包都不会和下次的 sendto 发送的数据包有任何粘包,这种在协议层发送的每个包都是独立的关系,我们叫做 该协议是有消息边界的协议,所以 UDP 是有消息边界的,我们不需要处理粘包分包问题。
''' 此为服务器端程序 ''' import socket server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建套接字 server_socket.bind(('127.0.0.1', 8889)) # 绑定的 IP 和端口 while True: # 接收数据: input("输入任何字符开始接收数据......") client_data, server_addr = server_socket.recvfrom(1024) # 接收客户端信息 client_data = client_data.decode("utf-8") # 解码字节流 if client_data == "exit": # 判断服务器是否申请结束会话 break print(client_data) server_socket.close()
''' 此为客户端程序 ''' import socket import time client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # 创建套接字 server_ipport = ("127.0.0.1", 8889) # 通信的服务器的 ip 和端口 # 发送数据 client_data = "hello" client_socket.sendto("老鸟".encode("utf-8"), server_ipport) # 发送信息 client_socket.sendto("python".encode("utf-8"), server_ipport) # 发送信息 client_socket.sendto("exit".encode("utf-8"), server_ipport) # 发送信息 client_socket.close() # 关闭套接字
我们先运行服务器代码,阻塞到 input 处。然后运行客户端代码,连续发送三条信息(“老鸟”,“python”,“exit”)。然后我们在服务器端输入任意字符,进入 recvfrom 函数,我们发现服务器端程序从 UDP 协议栈接收缓冲区内分三次收取这些信息。
我们分析以上基于 UDP 的服务器和客户端代码,发现和前面我们学的 TCP 协议有一些不同地方。
最后注意:绑定 UDP 端口和 TCP 端口互不冲突,也就是说,UDP 的 8889 端口与 TCP 的 8889 端口可以同时绑定使用。
了解 UDP 协议的特点。
会编写基于 UDP 协议的程序。
了解 UDP 协议和 TCP 协议的不同。
用 UDP 协议发送视频文件,接收方收到视频字节流后,计算出丢包率。
可以,挺清晰的