65.9K
CodeProject 正在变化。 阅读更多。
Home

简单的网络编程

starIconstarIconstarIconstarIconstarIcon

5.00/5 (4投票s)

2011 年 12 月 6 日

CPOL

5分钟阅读

viewsIcon

40489

downloadIcon

1350

一种简单的网络编程方法

引言

大约 5 年前,当我开始编程时,我曾怀揣着远大的梦想。我想从零开始构建一个完美无瑕的聊天系统,它必须快速、可靠且轻量级。

然而,对于新手程序员来说,大多数雄心勃勃的项目都会很快夭折,这个项目也不例外。我搜索并努力寻找一个合适的系统或代码,以便能够与一个中心化服务器上的两个客户端进行简单的通信。显然,这对我来说非常困难(直到几年后我才精通 Google 搜索),我找不到任何能完全满足我需求的东西。

几年过去了,我积累了更多技能,于是我决定,“嘿,我应该写那个聊天系统”。于是我照做了。结果很糟糕,但我学到了很多东西。RattleSnake 就是我学到的东西的一个例子。

背景

我想要一个灵活的系统,能够接受我给它的任何东西,并产生我想要的结果。这听起来可能很愚蠢,但请听我说。我希望能够序列化结构,或者在不改变发送方式的情况下发送自定义编码的字节数组。RattleSnake 就能做到这一点。

这个项目最初只是一个个人项目,但后来发展成了庞大的工程。RattleSnake 几乎可以处理你想要的任何事情,从客户端-服务器连接,到处理 UPnP。

RattleSnake 包含 4 个主要命名空间

  • RattleSnake.Client
    • RattleSnake.Client.Client
    • RattleSnake.Client.TcpClientEx
  • RattleSnake.Server
    • RattleSnake.Server.Server
    • RattleSnake.Server.TcpListenerEx
  • RattleSnake.Security
    • RattleSnake.Security.WhirlpoolManaged
      • 请注意,这个类并非我创作。我只是将其从 C# 转换而来。原始许可证和注释仍然保留,以归功于原作者。
    • RattleSnake.Security.MersenneTwister
      • WhirlpoolManaged 一样,我没有创建这个类。我只是将其从 C# 转换而来。原始许可证和注释仍然保留,以归功于原作者。
    • RattleSnake.Security.Encryption
  • RattleSnake.UPnP

每个命名空间的内容和功能都非常清晰。

我不得不进行一些继承,例如继承 TcpClientTcpListener 以便提供未来的功能(例如 MyBase.Active() 属性),并在我更新这个项目时使用。不过,目前 RattleSnake 相对完整,只差一些我想添加的新功能。

Using the Code

使用 RattleSnake 的客户端、服务器、UPnP 和安全功能极其简单。客户端和服务器完全是事件驱动的,这使得理解它们非常容易。

下面是一个使用客户端的简单示例

' This is for the Client. 
Dim _rsc As New RattleSnake.Client.RattleSnakeClient() 

' Now perform a connection
_rsc.Connect("127.0.0.1", 6110)  

要执行连接,只需要以上代码。但是,我们如何跟踪客户端何时连接?接收数据、断开连接或异常又如何处理呢?RattleSnakeClient 类提供了事件来处理所有这些情况。

Public Event ConnectionEstablished(ByVal sender As Object, _
    ByVal e As EventArgs.RattleSnakeClientConnectionEstablishedEventArgs)

当建立连接时,将触发此事件。传递的 EventArgs 包含以下属性:

  • IP - 返回客户端连接的 IP 地址(作为 String)。
  • Port - 返回客户端连接的端口号(作为 Port)。
Public Event DataReceived(ByVal sender As Object, _
    ByVal e As EventArgs.RattleSnakeClientDataReceivedEventArgs)

当通过连接传输 Data 时,将触发此事件。传递的 EventArgs 包含以下属性:

  • Data - 返回一个字节数组,其中包含接收到的所有数据。
  • Object - 尝试通过序列化返回一个表示接收到的 Data 的对象。如果序列化失败,则返回一个 New Object
Public Event Exception(ByVal sender As Object, _
    ByVal e As EventArgs.RattleSnakeClientExceptionEventArgs) 

RattleSnakeClient 抛出异常时,将触发此事件。传递的 EventArgs 包含以下属性:

  • Exception - 返回抛出的异常。

这些事件简单明了,并确保 RattleSnake 顺利运行。
使用 RattleSnake 发送数据同样极其简单。

'Define some random data in a Byte Array; filled with junk data or what not.
Dim _data As new Byte(255)

'Now send it with RattleSnake
_rsc.BeginSend(_data) 

使用 RattleSnake 发送数据就是这么简单。你也可以简单地将一个可序列化的 Object 传递给 .BeginSend() 方法,它也会被发送;RattleSnake 在内部使用了这个功能。

断开连接同样轻而易举。

'Disconnect.
_rsc.Disconnect(True)

RattleSnake 中,除非确实重要,否则 .Disconnect() 总是会取一个 True 值。这个 True 值会告诉 RattleSnake 通知对方正在发生断开连接。我这样做只是为了确保对方不会收到本可以避免的异常。

现在,简单介绍一下 RattleSnake 中的 UPnP 类。UPnP 类允许快速方便地在支持 UPnP 的设备上添加(或删除)端口映射。以下是 UPnP 类的方法、属性和枚举列表:

  • 协议
    • TCP
    • UDP
  • Add()
  • Remove()
  • Exists()
  • LocalIP()
  • Print()
  • Dispose()

每个方法都有 XML 风格的注释,所以我在这里不详细介绍,但在支持 UPnP 的设备上添加端口映射非常容易。

Using rs = New RattleSnake.UPnP.UPnP
        rs.Add(RattleSnake.UPnP.UPnP.LocalIP(), 100, 
    RattleSnake.UPnP.UPnP.Protocol.TCP, "Description")
End Using  

仅此而已就可以为支持 UPnP 的设备添加端口映射。该代码将映射添加到本地 IP 地址,端口号为 100,协议为 TCP,描述为 "Description"。删除操作同样简单。

Using rs = New RattleSnake.UPnP.UPnP
        rs.Remove(100, RattleSnake.UPnP.UPnP.Protocol.TCP)
End Using 

刚才添加的端口现在已被删除。Add()Remove() 例程在内部调用 Exists(),因此程序员不需要自己执行此操作(但是,该类会抛出 ArgumentException())。

总的来说,RattleSnake 不应该存在太多 bug。它已经经过了多次实际测试,几乎没有出现什么错误,但如果出现任何 bug,我会尽力尽快修复。

关注点

我应该指出,RattleSnake 已经经历了几次重写。截至 2011 年 12 月 5 日,这是 RattleSnake 的第三次重写,目的是提供更清晰、更高效的代码。UPnPRattleSnake 的一个近期添加功能,我为此花费了一些研究时间,以弄清楚如何在 Windows 中轻松实现它。我在这里使用的“轻松”这个词比较随意,因为相对简单,但需要一些琢磨才能使其正常工作(例如,它似乎只在 .NET 3.5 及以上版本中有效,因为 .NET 2.0 中没有暴露所需的接口)。

历史

  • 2011 年 12 月 5 日 - 初始发布
© . All rights reserved.