轻松实现点对点聊天





4.00/5 (8投票s)
2006 年 4 月 16 日
4分钟阅读

97714

5695
利用微软的Peer-to-Peer技术和Adrian Moore的封装,创建一个易于使用的聊天库。
引言
微软创建了一套用于创建Peer-to-Peer应用程序的技术。这些技术代表了可以用来构建多种类型应用程序的低级构建块。Adrian Moore在他的几篇CodeProject文章中解释了这些技术。他还将这些技术引入了托管编程世界。
在密歇根州立大学的高级项目中,微软要求我们创建一个类集,用于快速创建Peer-to-Peer应用程序。由于Adrian已经在这方面做了很多工作,我们决定扩展他的库,专注于轻松创建聊天风格的应用程序。本文将介绍我们是如何创建它的。
关于聊天
为了开始我们的库,我们研究了几种聊天应用程序。似乎我们走到哪里都能看到聊天。无论是在你最喜欢的即时通讯客户端中,还是在IRC的频道中,甚至是多人博客网站上,所有这些类型的互动都可以被认为是聊天,只是在命名和呈现上略有不同。
我们得出的结论是,所有这些风格的聊天应用程序都可以被视为一个“聊天室”,而不同的人在那里交换“消息”,这些消息会持续不同长度的时间。
使用图和记录
当我们研究微软和Adrian提供的Peer技术时,我们对图技术特别感兴趣。图可以被认为是记录的数据库,这与许多聊天应用程序的考虑方式相似:一个消息的聊天室。
因此,我们创建了一个模拟这种基本关系的类,并将其命名为Chatroom
。在我们的模型中,Chatroom
负责设置图并连接到同一聊天室中的对等节点所需的所有网络代码。下面是Connect()
方法的简化版本。
//start a graph for local use
_graph = new Peer.Graph.PeerGraph(this.Name);
//generate a unique identity to connect to the graph
_chatID = Guid.NewGuid();
ChatID = _chatID.ToString();
//create a local database in case it doesn't exist
Peer.Graph.PeerGraph.Create(this.Name, ChatID, DatabaseName);
//open the database once it's created
_graph.Open(DatabaseName, ChatID );
如您所见,我们首先创建一个图(如果已有人创建则会失败),然后打开它以连接到其他对等节点。Chatroom
还负责将消息转换为记录。下面是Send(Message)
方法的简化版本
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream memory = new MemoryStream();
Peer.Graph.PeerRecord record;
formatter.Serialize(memory, message);
record = _graph.CreatePeerRecord(CHAT_MESSAGE_RECORD_TYPE,
message.Lifetime);
record.DataAsStream = memory;
_graph.AddRecord(record);
如您所见,我们实际上将整个对象序列化为记录的数据。使用此方法可以使数据可靠,因为除非接收到完整的消息,否则无法反序列化。我们使用此方法传输聊天室中需要同步的所有数据。
事件
像大多数Windows API一样,Peer-to-Peer技术会发布程序可以监听的事件。通过订阅Peer事件,我们能够在库中发布专门针对用户和消息的事件。当数据库中添加记录时,我们确定记录的类型并触发正确的事件。下面是基于图事件确定触发哪个事件的简化版本。
Peer.Graph.PeerRecord record;
BinaryFormatter formatter = new BinaryFormatter();
switch (e.Action)
{
case Peer.Graph.PeerRecordAction.Added:
if (e.RecordType == USER_RECORD_TYPE)
{
//get the record from the database
record = this._graph.GetRecord(e.RecordId);
//deserialize the user instance embedded in the record
PeerChat.User user =
(PeerChat.User)formatter.Deserialize(record.DataAsStream);
//let anyone who wants to know, know that someone joined
if (this.UserJoined != null)
{
//attach the user to the user event
UserEventArgs args = new UserEventArgs(user);
UserJoined(this, args);
}
...
如您所见,我们只需从数据库中检索记录,并将其实例化为一个我们可以处理的对象。
UI 控件
在创建了基础设施所需的类之后,我们希望让开发人员能够轻松地创建Windows Forms应用程序。为此,我们创建了具有关联Chatroom
的自定义控件。我们使用了Chatroom
发布的事件来控制它们的行为。以UserList
控件为例,它提供了聊天室中在线状态的可视化表示。
m_chat_room.UserJoined += new
PeerChat.Chatroom.UserEventHandler(m_chat_room_UserJoined);
...
void m_chat_room_UserJoined(object sender, PeerChat.UserEventArgs e)
{
AddUserToList(e.User);
}
public void AddUserToList(PeerChat.User the_user)
{
if (this.InvokeRequired)
{
UserCallback methodToCall = new UserCallback(AddUserToList);
Invoke(methodToCall, new object[] { the_user });
}
else
{
this.Items.Add(the_user.Name);
}
}
InvokeRequired
标志的使用是因为从不同线程(Peer线程)更新Windows Forms控件是不安全的。在上面的示例中,加入Chatroom
的用户姓名被添加到列表框的Items
中。
结论
虽然Peer-to-Peer技术还有许多其他方面,但我们在项目中没有涉及它们,我们希望我们对这个领域的探索能够为使用这种技术的开发者节省一些时间。PeerChat库还有许多方面我们在本文中没有讨论,但如果您想了解更多,可以从页面顶部下载PeerChat的源代码。您也可以通过查看Adrian Moore的CodeProject文章来了解更多关于图的信息。
关于项目
PeerChat由Mike Fazio、Dan Lash、Carly Szekely和Tom Vollman在密歇根州立大学开发。该项目的网站位于此处。