Peer Graph - 交换私有数据






4.23/5 (3投票s)
2005年12月12日
4分钟阅读

86095

390
使用 Microsoft 的 Peer-to-Peer 技术在对等图(peer graph)中交换私有数据。
背景
Microsoft 的 Peer-to-Peer Graphing 技术为 Windows 对等应用程序提供了稳定、可靠且健壮的基础设施进行通信。对等节点使用 Peer Name Resolution Protocol (PNRP - 一个无服务器的 DNS) 在图中注册和发现其他对等节点。图是连接对等节点、服务和资源的对等网络的基础。对等节点可以是用户交互式应用程序、服务或资源。Graphing 允许数据在对等节点之间高效且可靠地传递。
Microsoft 的整个点对点技术通过最新的平台 SDK 以 C/C++ API 调用形式公开。但是,本文中的代码展示了如何使用 C# 从 .NET 托管代码调用这些 API。
引言
本文介绍了在对等图中交换私有数据的概念。这是上一篇文章的延续,上一篇文章展示了对等节点如何使用 Microsoft 的 Peer-to-Peer Graphing 技术打开和关闭私有连接。一旦对等节点之间建立连接,任何一方都可以通过该连接发送和接收数据。PeerOpenConnection
类提供了另外两个用于发送数据的方法和一个用于接收数据的方法。
发送数据
要发送数据,示例 PeerGraph
类提供了以下 internal
函数来发送字节数组。
internal void SendData(System.Int64 ConnectionId,
Guid Type, int Length, IntPtr Data)
{
IntPtr typeptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(Guid)));
Marshal.StructureToPtr(Type, typeptr, false);
uint hr = PeerGraphNative.PeerGraphSendData(hGraph,
ConnectionId, typeptr, (uint)Length, Data);
if (hr != 0) throw new PeerGraphException(hr);
}
SendData
方法调用底层的 PeerGraphSendData
API。连接 ID、消息类型、缓冲区长度和缓冲区作为参数传递。此方法在数据进入网络后立即返回,不等待确认。
示例 PeerOpenConnection
类实现了两个包装函数来简化数据发送。第一个方法允许发送字符串。
public void SendData(Guid Type, string Message)
{
IntPtr dataptr = Marshal.StringToHGlobalUni(Message);
int size = (Message.Length+1)*2;
graph.SendData(connectionId, Type, size, dataptr);
}
第二个方法提供了一个更通用的数据流来发送。MemoryStream
是在对等节点之间交换结构化数据的理想方式。这还允许传递文件流来发送文件的内容。
public void SendData(Guid Type, System.IO.Stream Data)
{
int size = (int)Data.Length;
byte[] data = new byte[size];
Data.Read(data, 0, size);
IntPtr dataptr = Marshal.AllocHGlobal(size);
Marshal.StructureToPtr(data, dataptr, false);
graph.SendData(connectionId, Type, size, dataptr);
}
在这两种情况下,都可以处理将托管数据封送到非托管指针的繁琐细节。
您可能已经注意到 SendData
方法接受一个 Type
参数。这个 GUID 值允许每种类型的消息都被唯一标识。这与 Windows 应用程序使用 WM_XXX
代码来标识消息相同。
数据接收事件
PeerGraph
类按照从另一个对等节点接收私有数据消息的顺序处理 PEER_GRAPH_EVENT_INCOMING_DATA
通知。
private void HandleEventIncomingData(IntPtr evptr)
{
PEER_EVENT_INCOMING_DATA ndata = (PEER_EVENT_INCOMING_DATA)
Marshal.PtrToStructure(evptr,
typeof(PEER_EVENT_INCOMING_DATA));
PeerOpenConnection cn = (PeerOpenConnection)OpenConnections[ndata.ullConnectionId];
if (cn != null)
{
PeerGraphDataReceiveEventArgs args = new
PeerGraphDataReceiveEventArgs(cn, ndata.type,
ndata.data.pbData, ndata.data.cbData);
cn.RaiseDataReceivedEvent(args);
}
}
在内部,PeerGraph
类维护一个哈希表,将所有连接 ID 映射到已打开的连接。快速查找允许传入通知在相应的、已打开的连接上触发 DataRecieved
事件。在这种情况下,RaiseDataReceivedEvent
函数处理此问题。
使用示例应用程序
示例应用程序首先允许您创建一个图(未加密的对等节点名称 0.TestGraph)并带有初始身份。第一个实例应该使用此身份打开。它将暂停几秒钟以查找其他实例,然后开始侦听。随后的每个应用程序实例都应该使用不同的身份打开图。这些实例将连接到最近的对等节点并进行同步。应用程序的每个实例都是一个对等节点。
左侧列表显示了所有操作和传入事件的诊断日志。双击以清除列表。
右侧列表显示了连接到图的所有对等节点的身份。双击一个对等节点以发起发送消息。会出现一个输入框,供您输入一些文本。关闭此窗口时,文本将发送到相应的对等节点。
private Guid WHISPER_MESSAGE_TYPE =
new Guid(0x4D5B2F11, 0x6522, 0x433B, 0x84,
0xEF, 0xA2, 0x98, 0xE6, 0x7, 0xBB, 0xBB);
private void OnConnectionOpened(object sender,
PeerGraphConnectionOpenedEventArgs e)
{
if (e.OpenConnection.ConnectionId == connectionId)
{
// send the data
e.OpenConnection.SendData(WHISPER_MESSAGE_TYPE, Message);
}
else // receiver opened, so bind for event
e.OpenConnection.DataReceived += new
PeerOpenConnection.DataReceivedHandler(OnDataReceived);
}
示例应用程序的 OnConnectionOpened
事件将连接 ID 与打开连接后返回的 ID 进行比较。匹配的 ID 表明打开连接并即将发送数据的对等节点。否则,它是接收数据的对等节点,因此它会绑定到 DataReceived
事件。
public void OnDataReceived(object sender,
PeerGraphDataReceiveEventArgs e)
{
// read message then close
LogMessage(e.OpenConnection.Connection.PeerName, e.DataAsString);
e.OpenConnection.Close();
}
示例应用程序的 DataRecieved
事件处理程序只是将收到的消息添加到诊断列表中并关闭连接。
关注点
示例应用程序展示了一种对等节点交换私有数据的非常简单的方法。然而,这是更完整的即时通讯风格应用程序的基础。也可以使用此技术在对等节点之间交换文件。
资源链接
我发现以下资源对于理解对等图形非常有帮助
结论
希望您觉得本文很有用。下一篇文章将重点介绍与图中的所有对等节点共享数据。敬请关注以下主题的更多文章
- 对等名称解析 - Windows Vista 增强功能
- 对等图形 - 记录
- 对等图形 - 属性
- 对等图形 - 搜索
- 对等组和身份
- 对等协作 - 附近的人
- 对等协作 - 端点
- 对等协作 - 能力
- 对等协作 - 在线状态
- 对等协作 - 邀请
如果您对其他主题有建议,请留言。
历史
初始版本。