36. UDP网络编程

打印 上一主题 下一主题

主题 849|帖子 849|积分 2547

一、什么是UDP协议

  相对于 TCP 协议,UDP 协议则是面向无连接的协议。使用 UDP 协议时,不必要建立连接,只必要知道对象的 IP 地址和端标语,就可以直接发数据包。但是,数据无法保证一定到达。固然用 UDP 传输数据不可靠,但它的优点是比 TCP 协议的速率快。对于不要求可靠到达的数据而言,就可以使用 UDP 协议。

   UDP 每次发送数据的时候,都必要写上汲取方的 IP 和 PORT;
  二、UDP网络编程

2.1、创建UDP服务器

  创建 UDP 服务器的伪代码如下:
  1. import socket                       # 导入socket模块
  2. ss =  socket.socket()               # 创建服务器套接字
  3. ss.bind()                           # 套接字与地址绑定
  4. while True:                         # 监听连接
  5.    cs = ss.recvfrom()/ss.sendto()   # 对话(接收/发送)
  6. ss.close()                          # 关闭服务器套接字
复制代码
  UDP 和 TCP 服务器之间的一个显著差别是,由于数据报套接字是无连接的,以是就没有为了通讯成功而使一个客户端连接到一个独立的套接字 “转换” 的操作。这些服务器仅仅汲取消息,并有可能回复数据。
  1. from socket import socket
  2. from socket import AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_REUSEADDR
  3. from time import ctime
  4. HOST = "127.0.0.1"
  5. PORT = 8080
  6. ADDRESS = (HOST, PORT)
  7. udp_server = socket(AF_INET, SOCK_DGRAM)                        # 创建服务器套接字
  8. udp_server.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)              # 解决端口占用问题
  9. udp_server.bind(ADDRESS)                                        # 套接字与地址绑定
  10. while True:                                                     # 通信循环
  11.     recv_data, client_addr = udp_server.recvfrom(1024)          # 服务端接收消息,单次最大接收为1024个字节
  12.     print(f"收到客户端【{client_addr}】数据:{recv_data.decode('utf-8')}")
  13.     udp_server.sendto(f"【{ctime()}】 {recv_data.decode('utf-8')}".encode("utf-8"), client_addr)     # 服务端发送消息
  14. udp_server.close()                                              # 关闭服务器套接字
复制代码
  对 socket() 的调用的差别之处仅仅在于,我们现在必要一个 数据报/UDP 套接字范例,但是 bind() 的调用方式与 TCP 服务器版本的相同。由于 UDP 是无连接的,以是这里没有调用 “监听传入的连接”。
2.2、创建UDP客户端

  创建 UDP 服务器的伪代码如下:
  1. import socket                       # 导入socket模块
  2. cs =  socket.socket()               # 创建客户端套接字
  3. while True:                         # 通信循环
  4.     cs.sendto()/cs.recvfrom()       # 对话(发送/接收)
  5. cs.close()                          # 关闭客户端套接字
复制代码
  UDP 客户端循环工作方式几乎和 TCP 客户端一样。唯一的区别是,事先不必要建立与 UDP 服务器的连接,只是简单的发送一条消息并期待服务器的回复。
  1. from socket import socket
  2. from socket import AF_INET, SOCK_DGRAM
  3. HOST = "127.0.0.1"
  4. PORT = 8080
  5. ADDRESS = (HOST, PORT)
  6. udp_client = socket(AF_INET, SOCK_DGRAM)                            # 创建客户器套接字
  7. while True:                                                         # 通信循环
  8.     send_data = input("请输入要发送的数据: ").strip()
  9.     udp_client.sendto(send_data.encode("utf-8"), ADDRESS)           # 客户端发送数据
  10.     recv_data, server_addr = udp_client.recvfrom(1024)              # 客户端接收数据,单次最大接收为1024个字节
  11.     print(f"收到服务端【{server_addr}】返回的数据:{recv_data.decode('utf-8')}")
  12. udp_client.close()                                                  # 关闭客户端套接字
复制代码
2.3、实行UDP服务器和客户端

  如果先运行客户端,那么将无法进行任何连接,由于没有服务器期待接受请求。服务器可以视为一个被动同伴,由于必须首先建立本身,然后被动的期待连接。另一方面,客户端是一个主动的合作同伴,由于它主动发起一个连接。换句话说,首先启动服务器(在任何客户端试图连接之前)。
  在开发中,创建这种 “友爱的” 退出方式的一种方法就是,将服务器的 while 循环放在一个 try-except 语句中的 except 子句中,并监控 EOFError 或 KeyboardInterrupt 异常,这样你就可以在 except 或 finally 子句中关闭服务器的套接字。
三、UDP广播

  UDP 广播是一种网络通讯的方式,在广域网或局域网中,UDP 广播可以向多个目的主机发送数据包,使得网络中的全部装备都能汲取到广播消息。使用广播之后,socket 只必要发送一次 UDP 数据,就可以发送给本局域网中的任何一台电脑相同的数据。
  1. import socket                       # 导入socket模块
  2. ss =  socket.socket()               # 创建服务器套接字
  3. ss.setsockopt()                     # 设置UDP套接字允许广播
  4. ss.bind()                           # 套接字与地址绑定
  5. while True:                         # 监听连接
  6.    cs = ss.recvfrom()/ss.sendto()   # 对话(接收/发送)
  7. ss.close()                          # 关闭服务器套接字
复制代码
  1. from socket import socket
  2. from socket import AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_BROADCAST
  3. from time import ctime
  4. HOST = "127.0.0.1"
  5. PORT = 8080
  6. ADDRESS = (HOST, PORT)
  7. BROADCAST_HOST = "<broadcast>"                                              # <broadcast>会自动改为本局域网的广播ip
  8. BROADCAST_PORT = 8086
  9. BROADCAST_ADDRESS = (BROADCAST_HOST, BROADCAST_PORT)
  10. udp_server = socket(AF_INET, SOCK_DGRAM)                                    # 创建服务器套接字
  11. udp_server.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)                          # 设置UDP允许广播
  12. udp_server.bind(ADDRESS)                                                    # 套接字与地址绑定
  13. while True:                                                                 # 通信循环
  14.     content = input("请输入你要广播的内容:")
  15.     udp_server.sendto(f"【{ctime()}】{content}".encode("utf-8"), BROADCAST_ADDRESS)  # 服务端发送广播内容
  16.     data, client_addr = udp_server.recvfrom(1024)                           # 服务端接收消息,单次最大接收为1024个字节
  17.     print(f"收到客户端【{client_addr}】返回的数据:{data.decode('utf-8')}")
  18. udp_server.close()                                                          # 关闭服务器套接字
复制代码
四、UDP聊天室

  1. from socket import socket
  2. from socket import AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_REUSEADDR
  3. from time import ctime
  4. from threading import Thread
  5. from queue import Queue
  6. HOST = "127.0.0.1"
  7. PORT = 8080
  8. ADDRESS = (HOST, PORT)
  9. udp_socket = socket(AF_INET, SOCK_DGRAM)                            # 创建服务器套接字
  10. udp_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)                  # 解决端口占用问题
  11. udp_socket.bind(ADDRESS)                                            # 套接字与地址绑定
  12. def send_msg(q):
  13.     while True:
  14.         dest_ip = input("请输入对方的IP地址:").strip()
  15.         dest_port = int(input("请输入对方的PORT:").strip())
  16.         while True:
  17.             msg = input("请输入要发送的数据:").strip()
  18.             if not msg:
  19.                 break
  20.             udp_socket.sendto(f"{msg}".encode("utf-8"), (dest_ip, dest_port))
  21.             info = f"【{ctime()}】向【{(dest_ip, dest_port)}】发送数据:{msg}"
  22.             q.put(info)
  23. def recv_msg(q):
  24.     while True:
  25.         try:
  26.             msg, dest_address = udp_socket.recvfrom(1024)           # 服务端接收消息,单次最大接收为1024个字节
  27.             info = f"【{ctime()}】收到【{dest_address}】发送的数据:{msg.decode('utf-8')}"
  28.             q.put(info)
  29.             print(info)
  30.         except:
  31.             pass
  32. def chat_history(q):
  33.     while True:
  34.         content = q.get()                                           # 从Queue中读取数据
  35.         # 将数据写入到文件中
  36.         with open("./chat.txt", "a", encoding="utf-8") as f:
  37.             f.write(content)
  38.             f.write("\n")
  39. if __name__ == "__main__":
  40.     q = Queue()                                                     # 创建一个队列
  41.     send_msg_thread = Thread(target=send_msg, args=(q,))            # 创建一个新的线程对象,用来发送数据
  42.     recv_msg_thread = Thread(target=recv_msg, args=(q,))            # 创建一个新的线程对象,用来接受数据
  43.     chat_history_thread = Thread(target=chat_history, args=(q,))    # 创建一个新的线程对象,用来保存聊天记录
  44.     send_msg_thread.start()
  45.     recv_msg_thread.start()
  46.     chat_history_thread.start()
  47.     send_msg_thread.join()
  48.     recv_msg_thread.join()
  49.     chat_history_thread.join()
  50.     udp_socket.close()
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

用户云卷云舒

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表