尧图精选

VMware虚拟机UDP通信实战:从网络配置到URSim位姿获取

🕒 发布时间:2026/10/1 23:32:44 📁 来源:尧图网络
最近群里好几个朋友在调试URSim问的问题几乎都一样虚拟机里机器人位姿数据明明在不断刷新宿主机上的程序就是收不到要么连不上端口要么收到的数据是乱码。这类问题看着是网络配置的锅其实背后牵扯的是主机、宿主机、虚拟机三者之间UDP通信的完整链路。今天我就把这个话题彻底聊透从虚拟网络原理、VMware网络模式选型到具体配置、代码示例和排障思路一次讲完。这篇文章适合三类人看一是在VMware里跑Ubuntu、需要和Windows宿主机联调的开发者二是做机器人仿真的朋友比如用URSim获取虚拟机器人位姿三是刚开始接触虚拟化网络搞不清NAT、桥接、仅主机模式区别的新手。看完你不仅能解决“收不到UDP数据”的问题还能明白为什么会出现这个问题。1. 先把链路讲清楚虚拟化环境中的UDP通信到底是怎么走的1.1 三个角色的身份确认主机、宿主机、虚拟机很多文章里把“主机”和“宿主机”混着用实际容易把人绕晕。为了后续讨论不跑偏先统一一下概念宿主机Host Machine真实物理机器比如你桌面上的Windows电脑。VMware Workstation就是跑在这台机器上的。虚拟机Virtual Machine由VMware创建、运行在宿主机里的虚拟计算机。比如VMware里的Ubuntu系统。主机Physical Host / Remote Host这个在不同语境下有歧义。在局域网通信场景里通常指和宿主机位于同一网络中的另一台物理机也就是“外部主机”在少数场景里也有人用“主机”指代宿主机本身。本文中我会根据上下文区分单独说“外部主机”时指宿主机之外的物理机说“宿主机”时指跑VMware的那台机器。搞清楚角色之后通信路径就有三种典型组合虚拟机内部程序 → 宿主机上的程序宿主机上的程序 → 虚拟机内部程序外部主机 → 宿主机/虚拟机 上的程序UDP通信本身不建立连接数据报文由发送方丢到网络上接收方在某个IP和端口上监听。看起来很简单但一旦把虚拟机这层虚拟化引进来路径上就多了虚拟网卡、虚拟交换机、NAT网关这些中间节点任何一个环节配置不对报文就丢了。1.2 UDP报文的走向虚拟网卡与VMnet虚拟交换机VMware Workstation安装之后会在宿主机上创建两块虚拟网卡VMnet1仅主机模式专用和VMnet8NAT模式专用。同时还有一块虚拟交换机负责把虚拟机的虚拟网卡和宿主机上的虚拟网卡桥接起来。拿最常见的“虚拟机发UDP给宿主机”举例虚拟机里的程序调用sendto()报文从Ubuntu的虚拟网卡比如ens33出去。报文进入VMware为虚拟机创建的虚拟交换机。虚拟交换机根据目标IP判断该把报文送到哪里。如果目标IP是宿主机的VMnet1地址比如192.168.56.1就直接从虚拟交换机送到宿主机VMnet1网卡。宿主机上的程序在192.168.56.1上监听收到数据。这里有个关键点虚拟机网卡和VMnet1网卡实际上是在同一个虚拟二层网络里它们之间的通信不经过物理网卡、不经过路由器纯粹是VMware在内存里模拟的交换。所以只要虚拟机网卡和宿主机VMnet1配置在同一网段UDP报文就能直达速度还非常快。1.3 为什么“虚拟机ping得通宿主机但UDP收不到”这么常见这是被问得最多的现象虚拟机里ping 192.168.56.1能通但往这个IP发UDP宿主机上的程序就是收不到。问题通常出在四个地方Ubuntu防火墙ufw默认可能拦截入站UDP。ping用的是ICMP很多配置里放行了ICMP但没放行UDP。Windows防火墙某些情况下宿主机的程序在监听UDP端口但Windows防火墙拦截了来自虚拟网卡的入站UDP。监听地址绑错程序只绑定了127.0.0.1没有绑定0.0.0.0或192.168.56.1。Socket类型不匹配发送方用UDP socket、接收方用TCP socket或者端口不一致。后面的排障章节会专门说怎么逐个排查这里先记住结论能ping通只代表ICMP链路通UDP能不能通还需要单独验证。2. 网络模式选型决定虚拟机能不能被宿主机和外部主机找到2.1 三种常用网络模式对比VMware Workstation给虚拟机提供了三种主要网络模式每种模式对应不同的通信场景。很多人在新建虚拟机时直接拉默认后面发现问题了才回去改不如一开始就选对。模式对应VMnet虚拟机能否访问外网宿主机能否访问虚拟机外部主机能否访问虚拟机适用场景NATVMnet8能能但需注意端口映射默认不能需要端口转发虚拟机只需要上网不需要被外部访问桥接无复用物理网卡能能能虚拟机需要和局域网内设备直接通信仅主机VMnet1不能能不能宿主机与虚拟机之间的隔离通信URSim场景首选NAT模式本质上是宿主机做了地址转换虚拟机发出的报文经过VMnet8出去源IP被替换成宿主机的IP所以外网设备看到的发起方是宿主机。反过来外部主动访问虚拟机就比较麻烦因为NAT没做端口映射时外部报文不知道往哪里转。桥接模式最简单粗暴虚拟机网卡直接桥接到物理网卡虚拟机和宿主机、外部主机都处在同一个物理局域网里大家都能互访。代价是依赖物理网络的DHCP或配置静态IP如果办公网络限制严格IP可能不够用或冲突。仅主机模式是我个人最推荐的调试模式宿主机和虚拟机通过VMnet1组成一个隔离局域网外部网络进不来但两者之间通信是完全可达的。做UDP调试时网络环境干净没有DHCP冲突没有广播风暴干扰非常适合URSim这种需要固定IP的场景。2.2 什么时候用哪种URSim场景分析URSim是Universal Robots官方提供的机器人仿真环境跑在VMware里默认配置非常“挑网络”它期望网络是仅主机模式虚拟机的IP通常是192.168.56.101宿主机对应VMnet1的IP是192.168.56.1。如果你用NAT模式跑URSim那大概率会遇到“宿主机连不上虚拟机的30001/30002端口”的问题。原因很简单NAT模式下VMware网段是192.168.x.0URSim里的模拟机器人控制器默认工作在192.168.56.101这个地址上两边根本不在一个网段。如果你用桥接模式跑URSim虚拟机可能分配到物理局域网里的随机IPURSim内部默认IP也未必能改过来同样会出现“IP不对”的问题。所以跑URSim获取位姿老老实实用仅主机模式。宿主机和虚拟机都在192.168.56.0/24网段URSim进程启动后监听在30001/30002/30003端口宿主机直接用Python或C连接即可。2.3 VMware网络编辑器实操子网IP与DHCP设置打开VMware Workstation菜单栏“编辑” → “虚拟网络编辑器”能看到VMnet1和VMnet8的信息。这里有几个关键点需要确认VMnet1仅主机的网段选中VMnet1看下面的子网IP默认一般是192.168.56.0。URSim场景建议保持默认因为虚拟机器人控制器默认就在这个网段。DHCP设置仅主机模式默认启用DHCP但URSim建议关闭DHCP或使用静态IP避免虚拟机的IP漂移。可以点击“DHCP设置”查看分配的地址范围。宿主机VMnet1网卡的IP在Windows的“网络连接”里找到“VMware Virtual Ethernet Adapter for VMnet1”设置静态IP为192.168.56.1子网掩码255.255.255.0。这一步经常被忽略不设置的话宿主机自己都不在这个网段虚拟机自然找不到宿主机。很多人在“虚拟网络编辑器”里改完VMnet1设置后发现没用因为忘了点右下角的“应用”或者Windows网卡没有同步更新。改完配置后建议同时看一下Windows网络连接里VMnet1网卡的IP两边要匹配。3. 实战配置从零搭一个宿主机虚拟机UDP收发环境3.1 VMware侧网卡添加与设置如果你已经建好了Ubuntu虚拟机但网卡配置不合适可以直接改设置关闭虚拟机电源或者关机。在VMware库中右键虚拟机 → “设置”。选择“网络适配器”把网络连接改成“仅主机模式Host-only”。如果虚拟机需要同时访问外网可以添加第二块网卡设为NAT模式。多网卡场景下注意路由优先级后面章节会说。保存设置后启动虚拟机。进Ubuntu后先敲两个命令确认网卡状态ip addr ip route正常情况下能看到ens33或ens32这样的网卡IP是192.168.56段的说明VMware侧已经通了。3.2 Ubuntu静态IP配置netplan方式Ubuntu 18.04以后的版本用netplan管理网络。配置文件一般在/etc/netplan/目录下文件名以.yaml结尾。以仅主机模式网卡ens33为例配置静态IPnetwork: version: 2 ethernets: ens33: addresses: - 192.168.56.101/24 dhcp4: false然后执行sudo netplan apply如果报错可以先用sudo netplan try试一下超时后会自动回滚避免把自己“锁在门外”。配置完成后ip addr确认IP生效。这里有个细节URSim的虚拟控制器在某些版本里会把网卡固定成192.168.56.101如果你把Ubuntu的IP设置成别的数字URSim内部可能仍然报192.168.56.101。为了避免混乱建议把虚拟机的IP也设置成192.168.56.101保持同一地址。3.3 用Python写一个UDP收发Demo回到标题的核心UDP通信。这里给一个最简但完整的Python示例用于验证链路。先从发送端虚拟机或宿主机任选一端开始。假设虚拟机是发送方IP是192.168.56.101宿主机是接收方IP是192.168.56.1端口取一个不常用的比如5005。接收方代码宿主机Windows上运行import socket sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((0.0.0.0, 5005)) print(UDP server listening on port 5005) while True: data, addr sock.recvfrom(2048) print(freceived from {addr}: {data.hex()} ({len(data)} bytes))发送方代码虚拟机Ubuntu上运行import socket sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) server_addr (192.168.56.1, 5005) sock.sendto(bhello from virtual machine, server_addr) print(message sent)运行顺序是先跑接收方再跑发送方。如果宿主机Windows终端里打印出received from (192.168.56.101, 端口号)说明链路已经通了。这里推荐多写一行data.hex()因为很多UDP报文并不是可读的ASCII文本二进制数据直接print(str)会变成乱码不利于排查。用十六进制打印一眼就能看出数据内容是否符合预期。3.4 用网络调试助手验证链路如果你不想写代码或者想先确认网络链路本身是否通可以用“网络调试助手”这类工具。这类工具一般有TCP Server、TCP Client、UDP Server、UDP Client四种模式。宿主机上开一个UDP Server端口写5005绑定地址为0.0.0.0。虚拟机里用另一个网络调试助手开UDP Client目标IP填192.168.56.1端口填5005。发送一条测试字符串看宿主机端是否收到。如果收到说明操作系统层面的UDP通路没问题之后可以放心检查应用层逻辑。如果收不到问题大概率在网络配置或防火墙直接跳到第5章排查。3.5 Windows宿主机防火墙放行UDP端口Windows默认防火墙对入站UDP限制比较多尤其是来自“公用网络”的报文。VMnet1网卡在Windows里通常被识别为“公用网络”所以即使VMware内部交换没问题Windows防火墙也可能把UDP包挡在宿主机之外。手动开放端口的方法打开“Windows安全中心” → “防火墙和网络保护” → “高级设置”。在左侧选择“入站规则” → 右侧“新建规则”。选择“端口” → 协议选“UDP” → 特定本地端口填5005或需要的范围。操作选“允许连接” → 配置文件全勾选 → 命名保存。还有一种临时验证方法直接把防火墙先关掉测试UDP通不通。通了之后再逐条放行规则定位哪条规则拦的。关防火墙只建议在隔离的VMware调试环境做物理网络上别乱关。4. URSim位姿获取虚拟机里仿真机器人的UDP数据怎么到宿主机4.1 URSim是什么位姿数据从哪个端口出来URSim是Universal Robots公司发布的仿真工具本质是一个预先配置好的Ubuntu虚拟机里面跑着机器人控制器的模拟程序。你在URSim里可以加载程序、启动运动虚拟控制器以固定频率向外发送机器人状态数据。这里有个容易混淆的点URSim的标准状态接口是TCP不是UDP。30001端口是Primary Client Interface30002端口是Secondary Client Interface30003端口是Real-Time Client Interface。其中30002以10Hz频率发送XML格式的机器人状态包含TCP坐标、关节角、速度等30003是125Hz的实时数据流。既然标题强调“UDP通信”那URSim场景有两种理解方式你自己的程序走TCP连30002端口解析XML获取位姿。这是官方标准做法。你在URSim里跑了自己写的UDP服务比如通过端口30004向外发UDP数据宿主机用UDP socket接收。无论哪种网络链路层的要求是一样的虚拟机IP固定、宿主机能访问虚拟机的相应端口、防火墙放行。下面我会把TCP和UDP两种方式都讲一遍TCP方式作为官方兜底UDP方式作为自定义场景参考。4.2 经典配置URSim默认IP与VMware仅主机模式URSim这个虚拟机的默认网络很特殊它期望自己运行在192.168.56.101而宿主机VMware的虚拟网卡在192.168.56.1。这个网段就是VMnet1仅主机模式的经典网段。配置步骤虚拟网络编辑器里确认VMnet1子网是192.168.56.0确保DHCP关闭或至少把192.168.56.101排除在动态分配范围之外。虚拟机设置里把网络适配器改为“仅主机模式”。启动URSim虚拟机启动后ip addr确认IP是192.168.56.101。宿主机Windows的VMnet1网卡IP设置为192.168.56.1。完成这四步后宿主机就能访问虚拟机的端口了。先用一个简单的命令验证ping 192.168.56.101能通之后再用Python连30002端口测试。4.3 宿主机Python连接URSim并解析位姿TCP方式既然URSim 30002端口是TCP这里用Python的socket库连接它接收数据并解析TCP坐标。import socket import xml.etree.ElementTree as ET HOST 192.168.56.101 PORT 30002 sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) sock.connect((HOST, PORT)) print(connected to URSim) while True: data sock.recv(4096) if not data: continue # UR secondary client data 格式前4字节是大端长度后面是XML xml_data data[4:] try: root ET.fromstring(xml_data) x root.findtext(./ActualTCPPose/X) y root.findtext(./ActualTCPPose/Y) z root.findtext(./ActualTCPPose/Z) rx root.findtext(./ActualTCPPose/RX) ry root.findtext(./ActualTCPPose/RY) rz root.findtext(./ActualTCPPose/RZ) print(fTCP pose: x{x}, y{y}, z{z}, rx{rx}, ry{ry}, rz{rz}) except ET.ParseError: passURSim发送的数据包前4个字节是数据长度大端序后面跟的是XML文本。如果直接把整个包丢给ET.fromstring会因为长度前缀报错所以要先data[4:]跳过长度头。如果输出坐标有值且不断变化说明链路完全打通。4.4 自定义UDP位姿服务虚拟机内发布、宿主机接收有些项目不走官方端口直接在URSim里跑自己的UDP服务比如把URSim里的机器人坐标周期性地发给宿主机。这种场景下虚拟机里运行一个UDP发送脚本宿主机里运行UDP接收脚本即可。虚拟机内发送脚本示例import socket import time import xml.etree.ElementTree as ET import urllib.request # 假设你已经通过某种方式拿到位姿这里只是示例 # 一般URSim里可以用Python来获取实际位姿这里演示一个简单的从30002取数据的辅助方式 import threading import socketserver这里提醒一下如果你只是想从URSim拿位姿直接连30002端口是最省事的。自定义UDP服务的意义在于当你做的不是“连接控制器”这种客户端-服务器模式而是需要把位姿广播给多个接收方或者嵌入到自己的UDP协议栈时才需要在URSim里搭一个UDP转发器。具体实现可以这样做虚拟机里写一个线程持续从30002端口拉取XML数据。解析出TCP坐标后用UDP socket发送到宿主机192.168.56.1的某端口比如6000。宿主机上开一个UDP监听端口6000不断显示收到的位姿。完整代码放在一起就长这样import socket import xml.etree.ElementTree as ET import threading # 从URSim 30002获取位姿 def get_tcp_pose(): sock socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.connect((127.0.0.1, 30002)) while True: data sock.recv(4096) if not data: continue xml_data data[4:] try: root ET.fromstring(xml_data) x float(root.findtext(./ActualTCPPose/X)) y float(root.findtext(./ActualTCPPose/Y)) z float(root.findtext(./ActualTCPPose/Z)) yield x, y, z except ET.ParseError: continue # UDP广播线程 def udp_broadcast(): udp_sock socket.socket(socket.AF_INET, socket.SOCK_DGRAM) target (192.168.56.1, 6000) for x, y, z in get_tcp_pose(): msg f{x:.6f},{y:.6f},{z:.6f}.encode() udp_sock.sendto(msg, target) if __name__ __main__: udp_broadcast()这个脚本在URSim虚拟机里跑起来后宿主机端监听6000端口即可看到持续的坐标流。4.5 收不到位姿的排查顺序如果宿主机收不到位姿数据按这个顺序排查效率最高ping 192.168.56.101确认虚拟机在线且同网段。在宿主机上用telnet 192.168.56.101 30002或Python连接30002端口确认Port活着。如果你走了UDP自定义数据流先确认UDP发送端脚本在URSim里跑了、报错没。检查宿主机的防火墙是否放行对应UDP/TCP端口。如果宿主机程序绑定的是192.168.56.1确认VMnet1网卡IP没问题。如果以上都对拿网络调试助手在两端同时监听同一个UDP端口验证原始报文是否抵达。我遇到过一种很隐蔽的情况虚拟机里URSim启动时网卡还没就绪导致URSim里的控制器绑定到了127.0.0.1上外部完全看不到端口。重启URSim虚拟机或确认URSim完全启动后再连接就能解决。5. 常见问题速查与经验心得5.1 故障排查表现象可能原因快速解决方案虚拟机与宿主机互相ping不通网卡模式不对或网段不一致统一使用仅主机模式确认IP都在192.168.56.0/24ping通但UDP收不到Windows防火墙拦截入站UDP新建入站规则放行UDP端口UDP发出去宿主机没反应宿主机程序没绑对外IPbind((0.0.0.0, port))URSim的30002端口连不上URSim默认IP期望是192.168.56.101虚拟机IP手动设为192.168.56.101外部主机找不到虚拟机仅主机模式默认外部不可达改用桥接模式虚拟机IP老是变DHCP分配导致关闭DHCP或配置静态IP重启后VMnet1网卡消失VMware服务被禁用确认“VMware NAT Service”和“VMware DHCP Service”为自动启动数据收到但内容和URSim文档对不上没去掉前4字节长度头先data[4:]再解析XML5.2 踩坑记录VMnet1有感叹号、多网卡路由混乱、DHCP租约先说VMnet1网卡感叹号。Windows设备管理器或网络连接里VMnet1显示黄色感叹号通常是VMware的网络驱动和系统有冲突或者网卡被禁用了。解决方式网卡右键 → 禁用再启用如果不行在VMware“虚拟网络编辑器”里点“还原默认设置”让VMware重建虚拟网卡。再说多网卡路由混乱。如果你给虚拟机设置了两块网卡一块仅主机、一块NAT默认路由可能跑到NAT那边去。那样从虚拟机发往192.168.56.1的数据可能走了NAT网卡再绕回来延迟高不说还可能不通。建议在多网卡场景下检查ip route确保192.168.56.0/24网段走了ens33仅主机那块的网卡。DHCP租约问题也很隐蔽。URSim场景下建议关闭VMnet1的DHCP功能因为URSim固定用192.168.56.101只要另一台虚拟机也抢到同一个IP通信就会乱套。在虚拟网络编辑器里设置“使用本地DHCP服务将IP地址分配给虚拟机”取消勾选即可。5.3 提升UDP调试效率的几个小技巧最后分享几个实操技巧能帮你少踩很多坑。第一优先用十六进制打印UDP数据。字符串打印在二进制报文面前毫无意义还会因为编码问题让你误判。写调试代码时保留hex()输出能快速看出数据边界和数据结构。第二网络调试助手和Python脚本对照测试。先用网络调试助手验证链路再用自己的脚本验证逻辑。链路不通是网络问题脚本收不到是代码问题两个工具交替用能快速二分定位。第三监听地址写0.0.0.0至少验证阶段不要写死特定IP。很多UDP收不到的问题是bind错了地址。开发阶段统一绑0.0.0.0确认链路通了再改成具体地址。第四VMware快照是调试利器。在改虚拟网络配置前打一个快照配置改崩了秒回滚不用重装系统。第五URSim场景下建议直接在宿主机上装一个Wireshark抓包时选择VMnet1网卡。这样你能清楚看到虚拟机发来的报文是否到达了宿主机的网络栈以及是从哪个端口、哪个IP发来的。抓包数据比任何日志都可靠。我在实际调试中最大的体会是UDP通信本身不难难的是把虚拟化网络的每一层都摆正。只要记得“虚拟机的网卡要在一个网段、目标IP要写对、Windows防火墙要放行、程序要监听到正确的地址”绝大多数问题都能当场解决。URSim位姿获取这件事本质上也只是先把网络打通再去解析数据而已。你按这个顺序从头走一遍基本不会卡住。
上一篇/下一篇内容由系统自动关联 返回资讯列表 →