You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python UDP聊天应用跨虚拟机通信失败问题求助

问题描述

我熟悉网络开发,用Python写了个基于UDP的聊天应用,把服务器部署在代理后的新虚拟机时,发现无法接收外部IP的UDP流量。

服务器核心代码(server.py)

import socket

localIP = ''
localPort = 1993
bufferSize = 1024

UDPServerSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
UDPServerSocket.bind((localIP, localPort))
print("UDP server up and listening")

while (True):

  bytesAddressPair = UDPServerSocket.recvfrom(bufferSize)

  message = bytesAddressPair[0]
  address = bytesAddressPair[1]


  clientMsg = "Message from Client:{}".format(message)
  clientIP = "Client IP Address:{}".format(address)
  print(clientMsg)
  print(clientIP)

客户端核心代码(client.py)

import socket

UDPClientSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
socket.setdefaulttimeout(10)
#I know this IP is a placeholder, it's not that way in my actual code
serverAddressPort = ("1.1.1.1", 1993)

bufferSize = 1024

def recvUDP():
  try:
    response = UDPClientSocket.recvfrom(bufferSize)
    return response
  except Exception as e:
    choice = confirm(
      f"Exception '{e}' occured while awaiting server response. Try again?")
    if choice:
      response = recvUDP()


def getUDP(message):
  UDPClientSocket.sendto(str.encode(message), serverAddressPort)
  try:
    response = UDPClientSocket.recvfrom(bufferSize)
    while response is None:
      time.sleep(0.1)
      response = recvUDP()
    return response
  except Exception as e:
    choice = confirm(
      f"Exception '{e}' occured while awaiting server response. Try again?")
    if choice:
      response = getUDP(message)

def connect():

  response = getUDP("initial")

  if response is None:
    sys.exit()

  print("Initial packet recieved")
  
  
connect()

异常现象

  • 两台机器间无法通过UDP通信
  • 服务器用nc -L -p 1993、客户端用curl测试时可正常接收数据包
  • 尝试将服务器绑定到公网IP时,socket模块提示无法绑定

解决建议

1. 确认代理与虚拟机防火墙配置

  • 检查代理设备(NAT网关、防火墙等)的UDP转发规则:确保外部IP的1993端口已转发到虚拟机内网IP的1993端口,且明确指定转发UDP协议(部分代理默认只处理TCP)。
  • 开放虚拟机内网防火墙的UDP 1993端口:
    • Ubuntu/Debian:执行ufw allow 1993/udp
    • CentOS/RHEL:执行firewall-cmd --add-port=1993/udp --permanent && firewall-cmd --reload

2. 修正服务器代码逻辑

  • 绑定''(即0.0.0.0)是正确操作,代表监听所有网卡,无需绑定公网IP(虚拟机的公网IP实际在代理设备上,本机仅持有内网IP)。可添加代码验证监听状态:
    # 在bind后添加
    print(f"Listening on {UDPServerSocket.getsockname()}")
    
  • 原服务器仅接收数据不回复,导致客户端超时等待,需添加响应逻辑:
    # 在print(clientIP)后添加
    msgFromServer = "Message received"
    bytesToSend = str.encode(msgFromServer)
    UDPServerSocket.sendto(bytesToSend, address)
    

3. 修复客户端代码缺陷

  • 补充缺失的模块导入:
    import time
    import sys
    # 需根据实际使用的confirm函数补充导入,例如tkinter的消息框:
    from tkinter.messagebox import askyesno as confirm
    
  • 完善异常分支的返回逻辑,避免无返回值导致的逻辑中断:
    def recvUDP():
      try:
        response = UDPClientSocket.recvfrom(bufferSize)
        return response
      except Exception as e:
        choice = confirm(f"Exception '{e}' occured while awaiting server response. Try again?")
        if choice:
          return recvUDP()
        else:
          return None
    

4. 网络抓包排查

  • 在虚拟机内执行tcpdump -i any udp port 1993,确认是否收到客户端的UDP数据包:
    • 抓不到包:代理转发规则存在问题
    • 能抓到但服务器无输出:Python代码监听逻辑异常
  • 客户端侧也可通过tcpdump验证数据包是否正常发出,未被本地防火墙拦截

内容的提问来源于stack exchange,提问作者MrToenails

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 19:22:55