製作您自己的整合服務
從 Windows 10 年度更新版開始,任何人都可以使用 Hyper-V 套接字,讓 Hyper-V 主機與其虛擬機之間進行通訊的應用程式 -- Windows Socket 具有新的位址系列和專用端點,以針對虛擬機為目標。 透過 Hyper-V 套接字的所有通訊都會執行,而不使用網路功能,而且所有數據都會保留在相同的物理記憶體上。 使用 Hyper-V 套接字的應用程式類似於 Hyper-V 的整合服務。
本檔逐步解說如何建立以 Hyper-V 套接字為基礎的簡單程式。
支援的主機OS
- Windows 10 和更新版本
- Windows Server 2016 和更新版本
支援的客體OS
- Windows 10 和更新版本
- Windows Server 2016 和更新版本
- Linux 客體與 Linux Integration Services。 請參閱 Windows 上 Hyper-V 支援的 Linux 和 FreeBSD 虛擬機
注意
支援的 Linux 客體必須對下列項目提供核心支援:
CONFIG_VSOCKET=y
CONFIG_HYPERV_VSOCKETS=y
功能和限制
- 支援核心模式或使用者模式動作
- 僅限數據流
- 沒有區塊記憶體(不是備份/視訊的最佳選項)
開始使用
需求:
- C/C++編譯程式。 如果您沒有 Visual Studio Community,請查看 Visual Studio Community
- Windows SDK -- 預安裝在 Visual Studio 2015 與 Update 3 和更新版本中。
- 執行其中一部具有至少一部虛擬計算機所指定主機作業系統的計算機。 -- 這是用來測試您的應用程式。
注意: Hyper-V 套接字的 API 在 Windows 10 年度更新版中公開推出。 使用 HVSocket 的應用程式將在任何 Windows 10 主機和客體上執行,但僅限使用 Windows SDK 組建 14290 之後的版本進行開發。
註冊新的應用程式
若要使用 Hyper-V 套接字,應用程式必須向 Hyper-V 主機的登錄註冊。
藉由在登錄中註冊服務,您可以取得:
- 啟用、停用及列出可用服務的 WMI 管理
- 直接與虛擬機通訊的許可權
下列 PowerShell 將會註冊名為 「HV Socket Demo」 的新應用程式。 這必須以系統管理員身分執行。 下列手動指示。
$friendlyName = "HV Socket Demo"
# Create a new random GUID. Add it to the services list
$service = New-Item -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices" -Name ((New-Guid).Guid)
# Set a friendly name
$service.SetValue("ElementName", $friendlyName)
# Copy GUID to clipboard for later use
$service.PSChildName | clip.exe
登錄位置和資訊:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices\
在此登錄位置中,您會看到數個 GUID。 這些都是我們的內建服務。
每個服務登入中的資訊:
Service GUID
ElementName (REG_SZ)
-- 這是服務的易記名稱
若要註冊您自己的服務,請使用您自己的 GUID 和易記名稱建立新的登錄機碼。
易記名稱將會與新的應用程式相關聯。 其會出現在性能計數器和 GUID 不適用的地方。
登錄項目看起來像這樣:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Virtualization\GuestCommunicationServices\
999E53D4-3D5C-4C3E-8779-BED06EC056E1\
ElementName REG_SZ VM Session Service
YourGUID\
ElementName REG_SZ Your Service Friendly Name
注意
Linux 客體的服務 GUID 使用 VSOCK 通訊協定,透過 svm_cid
和 svm_port
(而非 guid) 定址。 為了彌補與 Windows 之間的這種不一致情形,使用知名的 GUID 做為主機上的服務範本,這會在客體中轉譯為連接埠。 若要自訂您的服務 GUID,只需將第一個「00000000」變更為所需的連接埠號碼。 例如:「00000ac9」 是埠 2761。
// Hyper-V Socket Linux guest VSOCK template GUID
struct __declspec(uuid("00000000-facb-11e6-bd58-64006a7986d3")) VSockTemplate{};
/*
* GUID example = __uuidof(VSockTemplate);
* example.Data1 = 2761; // 0x00000AC9
*/
提示: 若要在 PowerShell 中產生 GUID 並將它複製到剪貼簿,請執行:
(New-Guid).Guid | clip.exe
建立 Hyper-V 套接字
在最基本的案例中,定義套接字需要位址系列、連線類型和通訊協定。
以下是簡單的 套接字定義
// Windows
SOCKET WSAAPI socket(
_In_ int af,
_In_ int type,
_In_ int protocol
);
// Linux guest
int socket(int domain, int type, int protocol);
針對 Hyper-V 套接字:
- 位址家族 -
AF_HYPERV
(Windows) 或AF_VSOCK
(Linux 客體) - 類型-
SOCK_STREAM
- 通訊協定 -
HV_PROTOCOL_RAW
(Windows) 或0
(Linux 客體)
以下是範例宣告/具現化:
// Windows
SOCKET sock = socket(AF_HYPERV, SOCK_STREAM, HV_PROTOCOL_RAW);
// Linux guest
int sock = socket(AF_VSOCK, SOCK_STREAM, 0);
系結至 Hyper-V 套接字
系結會將套接字與連線資訊產生關聯。
函式定義會複製於下方以供串連,請在這裡深入了解系結。
// Windows
int bind(
_In_ SOCKET s,
_In_ const struct sockaddr *name,
_In_ int namelen
);
// Linux guest
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
與標準因特網通訊協定位址系列 (sockaddr) 的套接字位址 (AF_INET
sockaddr) 不同,這些位址是由主機計算機的 IP 位址和該主機上的埠號碼所組成,則使用虛擬機的標識符和上面定義的應用程式識別符來建立連線的套接字位址 AF_HYPERV
。 如果繫結來自 Linux 客體,AF_VSOCK
使用 svm_cid
和 svm_port
。
由於 Hyper-V 套接字不相依於網路堆疊、TCP/IP、DNS 等。套接字端點需要非 IP,而非主機名,且格式仍明確描述連線。
以下是 Hyper-V 套接字套接字地址的定義:
// Windows
struct SOCKADDR_HV
{
ADDRESS_FAMILY Family;
USHORT Reserved;
GUID VmId;
GUID ServiceId;
};
// Linux guest
// See include/uapi/linux/vm_sockets.h for more information.
struct sockaddr_vm {
__kernel_sa_family_t svm_family;
unsigned short svm_reserved1;
unsigned int svm_port;
unsigned int svm_cid;
unsigned char svm_zero[sizeof(struct sockaddr) -
sizeof(sa_family_t) -
sizeof(unsigned short) -
sizeof(unsigned int) - sizeof(unsigned int)];
};
除了IP或主機名之外,AF_HYPERV端點嚴重依賴兩個 GUID:
VM 識別碼 – 這是每個 VM 指派的唯一標識符。 您可以使用下列 PowerShell 代碼段找到 VM 的識別碼。
(Get-VM -Name $VMName).Id
服務標識碼 – 如上所述的 GUID,應用程式會在 Hyper-V 主機登錄中註冊。
當連線不是特定虛擬機時,也有一組可用的 VMID 通配符。
VMID 通配符
名稱 | GUID | 描述 |
---|---|---|
HV_GUID_ZERO | 00000000-0000-0000-0000-000000000000 | 接聽程式應該系結至此 VmId,以接受來自所有分割區的連線。 |
HV_GUID_WILDCARD | 00000000-0000-0000-0000-000000000000 | 接聽程式應該系結至此 VmId,以接受來自所有分割區的連線。 |
HV_GUID_BROADCAST | FFFFFFFF-FFFF-FFFF-FFFF-FFFFFFFFFFFF | |
HV_GUID_CHILDREN | 90db8b89-0d35-4f79-8ce9-49ea0ac8b7cd | 子系的通配符位址。 接聽程式應該系結至此 VmId,以接受其子系的連線。 |
HV_GUID_LOOPBACK | e0e16197-dd56-4a10-9195-5ee7a155a838 | 回送位址。 使用此 VmId 會連線到與連接器相同的分割區。 |
HV_GUID_PARENT | a42e7cda-d03f-480c-9cc2-a4de20abb878 | 父位址。 使用此 VmId 會連線到連接器的父分割區。* |
* HV_GUID_PARENT
虛擬機的父代是其主機。 容器的父代是容器的主機。
從虛擬機中執行的容器連線將會連線到裝載容器的 VM。
接聽此 VmId 接受來自:(內部容器):容器主機的連線。
(在 VM 內:容器主機/無容器):VM 主機。
(不在 VM 內:容器主機/無容器):不支援。
支援的套接字命令
套接字() Bind() Connect() Send() Listen() Accept() Accept()
HvSocket 套接字選項
名稱 | 類型 | 描述 |
---|---|---|
HVSOCKET_CONNECTED_SUSPEND | ULONG | 當這個套接字選項設定為非零值套接字時,虛擬機暫停時不會中斷連線。 |