一、背景
在之前的分享中测试了pve宿主机与linux虚拟机通过串口通信的原理,通过启动命令发现了关联文件/var/run/qemu-server/104.qga和org.qemu.guest_agent.0设备通信,然而在windows虚拟机中无法识别串口设备。
-chardev socket,path=/var/run/qemu-server/104.qga,server=on,wait=off,id=qga0
-device virtio-serial,id=qga0,bus=pci.0,addr=0x8
-device virtserialport,chardev=qga0,name=org.qemu.guest_agent.0
二、分析过程
观察串口设备发现,我们配置的虚拟串口在设备管理器中无法观察到,编写程序也无法读取到(特意通过go语言测试)。
添加了一个串行端口的硬件后发现多了对应的通信端口,由此可以断定虚拟串口和硬件串口在虚拟机中是有区别的。
之后通过查阅资料,发现windows的虚拟串口是通过虚拟机内的管道和宿主机进行通信的,为了验证这一假设特意执行了guest-agent的启动文件。
由于以普通用户身份运行,因此无打开管道权限因此报错, \\.\Global\org.qemu.guest_agent.0 这个管道就是咱们之前配置的串口设备的名称。
三、验证猜想
将编写好的go代码编译成exe文件放入虚拟机中运行
func main() {
pipePath := `\\.\Global\org.qemu.guest_agent.0`
// 将管道路径转换为UTF-16编码
pipePathUTF16, err := syscall.UTF16PtrFromString(pipePath)
if err != nil {
fmt.Println("Error converting string to UTF-16:", err)
return
}
// 调用CreateFile函数打开命名管道
handle, err := syscall.CreateFile(
pipePathUTF16,
syscall.GENERIC_READ|syscall.GENERIC_WRITE,
syscall.FILE_SHARE_READ|syscall.FILE_SHARE_WRITE,
nil,
syscall.OPEN_EXISTING,
0,
0,
)
if err != nil {
fmt.Println("Error opening named pipe:", err)
return
}
fmt.Println("连接成功")
defer syscall.CloseHandle(handle)
// 读取数据
var buf [1024]byte
var bytesRead uint32
for {
err = syscall.ReadFile(handle, buf[:], &bytesRead, nil)
if err != nil {
fmt.Println(err)
time.Sleep(500 * time.Millisecond)
} else {
fmt.Printf("Read %d bytes from named pipe: %s\n", bytesRead, buf[:bytesRead])
}
}
}
再通过之前的socket链接命令,链接宿主机上的串口文件。
socat - UNIX-CONNECT:/var/run/qemu-server/104.qga
打开传入虚拟机的exe文件(管理员身份打开)
宿主机上的终端输入随意字符
在windows虚拟机中都可以收到
由此可以断定,宿主机通过虚拟串口的方式和windows虚拟机机中的管道通信,实现虚拟串口通信。