P2P 通信 - 代理监听器和代理客户端






3.67/5 (3投票s)
通过 Web 代理进行通信的监听器和客户端对象的实现。
引言
沟通是我在工作项目和纯粹娱乐性项目中都有很多经验的问题。.NET Remoting 使沟通更加容易,但如果你用过它并遇到过“Remoting Exception”错误,你就会明白为什么我不喜欢它。希望 WCF 能纠正其中一些问题。无论如何,如果你想进行 P2P(点对点)通信,你就必须处理像 UPNP、VPN 或某种代理这样的东西。这是我的 Web 代理实现。
背景
P2P 通信是我在应用程序中遇到的几次问题。我做过几个 Messenger 类应用程序,它们通过 TcpClients
和 TcpListener
进行通信。使用它们的唯一问题是,你的通信仅限于你的本地局域网。最近,我做了一个与多个 Web 服务通信的 Messenger 应用程序,它会定期轮询它们以获取新的用户列表、消息等。这可以正常工作,但基于一群客户端轮询 Web 服务器的通信并不好。下面是我解决此问题方案的概述。这些线代表发送到 HttpHandler
Server.ashx 的 WebRequests
,它正在等待另一个客户端将其数据发送到其终端。我模仿了 TcpClient
和 TcpListener
,并在它们之间插入了一个代理。问题解决了,在很大程度上。

Using the Code
在尝试使用这些对象之前,我假设你具备套接字通信的基本知识,并且使用过 TcpClients
和 TcpListeners
。我创建的代理版本非常相似,只是 ProxyClient
有一个 SendData
方法和一个 Receiving
事件,而不是一个你可以读写的 Stream
。
你需要做的第一件事就是让代理 Web 服务器运行起来。如果你打开代理解决方案,我指的是 ProxyService
网站。如果你对其进行任何修改,请确保下面的 web.config 行保持不变。这会注册 HttpHandler
Server.ashx。
<system.web>
<httpHandlers>
<add verb="*" path="*.ashx" type="ProxyServer.Server, ProxyServer"/>
</httpHandlers>
接下来,你需要建立一些连接。创建一个 ProxyListener
来开始监听,创建一个 ProxyClient
来连接它。为了使事情更简单,你想从 ProxyClient
发送到 ProxyClient
的任何对象都需要继承 ProxyCommon
项目中的 DataMessage
。这会给你的对象一个 SendEndPoint
和 RecieverEndPoint
。如果你想做一个客户端/服务器应用程序,你的服务器端代码看起来会像这样。
App.Config
<appSettings>
<add key="ProxyServer" value="https://:52318/ProxyService/Server.ashx"/>
<add key="ProxyServerName" value="Test Server"/>
</appSettings>
主机通信
string ServerName = ConfigurationManager.AppSettings["ProxyServerName"];
ProxyListener Listener = new ProxyListener(ServerName);
Listener.Start();
ProxyClient Client = Listener.AcceptProxyClient();
string Txt = "Some message I want to send";
StringMessage Msg = new StringMessage(Txt, Client.ClientEndPoint, Client.ServerEndPoint);
Client.SendData(Msg.ToByteArray());
现在是客户端。ProxyListener
基于 ServerName
开始监听。代理服务器将其用作键,并为其创建一个 EndPoint
。当你创建一个 ProxyClient
来与监听器通信时,它连接到相同的 ServerName
。代理服务器映射 EndPoints
,然后两个 ProxyClients
都准备好通信。
ProxyClient Client = new ProxyClient();
Client.Recieving += new EventHandler<RecievingEventArgs>(Client_Recieving);
string ServerName = ConfigurationManager.AppSettings["ProxyServerName"];
Client.Connect(ServerName);
string Txt = "Some message I want to send";
StringMessage Msg = new StringMessage(Txt, Client.ClientEndPoint, Client.ServerEndPoint);
Client.SendData(Msg.ToByteArray());
void Client_Recieving(object sender, RecievingEventArgs e)
{
StringMessage Msg = new StringMessage(e.Data);
//The Client received a message, do something with it!
}
关注点
ProxyClient
类与你可能熟悉的TcpClient
类之间的一个主要区别是,你无法访问单个Stream
来进行读写。这是因为底层的stream
来自HttpWebRequest
和WebResponse
。- 这个想法有一些我还没有解决的缺陷。由于代理存在于 Web 服务器上,并且在应用程序缓存中存储了消息队列、终端等,如果 Web 服务器重启,你的连接就会丢失,需要重新建立。如果你使用的是 GoDaddy 等共享托管服务,这个问题可能会更严重,因为 GoDaddy 似乎每天都会重启一次。 ;-)
- 这种方法绝对适用于发送小的 P2P 信息。我考虑过通过它发送小文件或序列化对象,但仅此而已。你的通信速度会比直接使用套接字连接慢,因为数据流必须通过 Web 服务器。如果你想真正地 P2P 流式传输大量数据,这可能不够快。
历史
- 2008 年 4 月 20 日:首次发布
这是我第一次尝试为 P2P 通信编写 Client
和 Listener
包装器。这是一个进行中的项目,所以我乐于接受建议。一旦我对这种通信方式有了一定的完善,我计划编写另一个更适合网络游戏、视频流等通信的包装器。如果有人有关于如何使用 UPNP / 端口转发 / 隧道进行 P2P 通信的建议,请告诉我。