《老鸟python 系列》视频上线了,全网稀缺资源,涵盖python人工智能教程,爬虫教程,web教程,数据分析教程以及界面库和服务器教程,以及各个方向的主流实用项目,手把手带你从零开始进阶高手之路!点击 链接 查看详情




UDP编程

阅读:188964491    分享到

TCP 就如打电话一样,要先建立连接,然后才能通信,这样可以保证我们通信的内容完整性。而 UDP 则是面向无连接的协议,使用 UDP 协议时,不需要建立连接,只需要知道对方的 IP 地址和端口号,就可以直接发数据包。但是,我们无法确保我们发的数据能不能或能不能全部到达对方。

使用 UDP 协议

服务器首先需要绑定端口,创建 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 有消息边界

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 协议有一些不同地方。

  • 服务器端不需要 accept,客户端不需要 connect。
  • 发送数据用的是函数 sendto,接收数据用的是函数 recvfrom。
  • recvfrom 收到的信息不但含有发送方发送的数据内容,还有发送方的 ip 和端口号。
  • sendto 可以发送空字节流,recvfrom 也会收到空字节流。
  • TCP 协议无消息边界,UDP 协议有消息边界。
  • 当调用 close 关闭套接字的时候,不会向对方发送一个空字节流。

最后注意:绑定 UDP 端口和 TCP 端口互不冲突,也就是说,UDP 的 8889 端口与 TCP 的 8889 端口可以同时绑定使用。

本节重要知识点

了解 UDP 协议的特点。

会编写基于 UDP 协议的程序。

了解 UDP 协议和 TCP 协议的不同。

作业

用 UDP 协议发送视频文件,接收方收到视频字节流后,计算出丢包率。


如果以上内容对您有帮助,请老板用微信扫一下赞赏码,赞赏后加微信号 birdpython 领取免费视频。


登录后评论

user_image
麦兆辉
2020年1月9日 12:54 回复

可以,挺清晰的


user_image
路人甲
2019年12月28日 13:07 回复

UDP 简单


user_image
lookas2001
2019年10月24日 19:39 回复

十分清楚的解释,膜拜作者大大!


user_image
王二小
2019年10月16日 05:34 回复

UDP 就不用解决粘包分包了,因为他是有消息边界的


user_image
邪叫教主
2019年9月12日 00:52 回复

这节课学着一点都不费劲