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

使用 MSN 协议的 TCP 客户端

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.09/5 (8投票s)

2004年7月20日

3分钟阅读

viewsIcon

109168

downloadIcon

560

使用 MSN 协议的 TCP 客户端

引言

这是一个我发起的用于通信的消息传递平台项目。MSN 协议是选择的渠道之一,因为它具有“始终在线和互联网可用”的特性。

基于 MSN 协议的消息传递就像任何其他基于 TCP 的客户端程序一样,这意味着 Winsock 编程。通过异步处理,我们将使程序响应更好。我更希望如此,该程序应该为每个在线的 MSN ID 分叉自己的线程,以便它可以使用单独的通道广播消息。因此,它需要多线程处理能力。

我已经在 VB.Net 下开发了它,因为 .Net 提供了方便的类来简化这些工作。与只有 VC 才能强大支持这些要求的日子相比,我仍然记得我开发的多线程基于套接字的服务器模块。但后来我遇到了一个不同的问题。

在开发过程中,我遇到了 3 个主要挑战

  1. MSN 协议通信
  2. VB.Net 下的 MD5 散列
  3. 多线程异步处理 TCP 客户端

使用代码

MSN 协议通信

  1. 有几个网站维护了关于 MSN 协议的信息。 MSN Messenger 协议 肯定是一个不容错过的有趣网站。
  2. 坦白地说,我在 VB.Net 下获得正确的序列以使其工作时遇到了问题,尤其是在登录服务器时。直到我遇到了 CodeProject 网站上的另一个项目文件,它演示了 MSN 连接 – 连接到 MSN
  3. 我在 VB.Net 下得到了它,以及 MSN 挑战处理

MD5 散列

MSN 登录后,它将在稍后收到质询密钥,我们需要通过 MD5 散列该密钥以及原始密钥来响应密钥,以便保持在线状态。当前版本将等待直到 MSN 服务器确认质询,然后多个线程将为每个在线 MSN ID 分叉,向它们发送消息。

Function MD5Encrypt(ByVal sInput As String) As String

        Dim bytHashValue() As Byte

        Dim bytMsgValue() As Byte

        Dim Ue As ASCIIEncoding = New ASCIIEncoding

        Dim md5 As New MD5CryptoServiceProvider

        bytMsgValue = Ue.GetBytes(sInput)

        LogToFile("MD5 Key: " + sInput)

        bytHashValue = md5.ComputeHash(bytMsgValue)

        Dim sOutput As New StringBuilder

        Dim iloop As Integer

        For iloop = 0 To bytHashValue.Length – 1

            sOutput.Append(bytHashValue(iloop).ToString("X2"))

        Next

        Return sOutput.ToString

End Function

异步与多线程

这是最具挑战性的部分。代码作为一个单线程工作是正确的。在调用 BeginRead 之后,通过 TcpClient 接收到的任何下一个传入数据都将通过 SocketIncomingMsg 响应给 AsyncCallBackEndRead 将捕获 Byte 流中的传入数据。

   readCallBack = New AsyncCallback(AddressOf SocketIncomingMsg)

   tcpClient.GetStream.BeginRead(bytDataRead, 0, 1024, 
         readCallBack, tcpClient.GetStream)

   SendMSNCmd("SYN", "1")


        Private Sub SocketIncomingMsg(ByVal arMsg As IAsyncResult)

               Dim intCount As Integer

               intCount = tcpClient.GetStream.EndRead(arMsg)

               ……

        End Sub

当我仅通过触发子例程模块(示例:btnTestCon 点击事件)来启动异步时,一切都很好。

 
        Start_MSN()
 

当我通过分叉另一个线程来处理时,它将无法从 TCPClient 读取数据,EndRead 将只返回一个错误。例如“无法从传输连接读取数据”。同样,对于分叉多个线程的部分,每个线程对应一个在线 MSN ID。它们都失败于同一点。

  Dim MSNThread As Threading.Thread = New Threading.Thread(AddressOf Start_MSN)

  MSNThread.Start()

我尝试捕获异常,并遵循 MSDN 文档,包括内部异常。但消息并没有多大帮助,(什么是错误 995 ??)

        Catch e As Exception

               LogToFile(e.InnerException.ToString())
 

         Exception Output:

'System.Net.Sockets.SocketException: 
'The I/O operation has been aborted because of either 
'a thread exit or an application request
'at System.Net.Sockets.Socket.EndReceive(IAsyncResult asyncResult)
'at System.Net.Sockets.NetworkStream.EndRead(IAsyncResult asyncResult)
'995

 

我尝试了许多其他方法,但都没有成功。最后我专注于 EndRead,这是否与多线程环境下的异步有关?所以我 在 BeginRead 之后调用了同步处理。

        readCallBack = New AsyncCallback(AddressOf SocketIncomingMsg)

        Dim iarReturn As IAsyncResult = tcpClient.GetStream.BeginRead(bytDataRead, _
         0, 1024, readCallBack, tcpClient.GetStream)

        iarReturn.AsyncWaitHandle.WaitOne()
 

它奏效了!!!

关注点

与以前的 VB 版本相比,VB.Net 下的多线程编程肯定更稳定,在调试和暂停之间,开发工具包不会突然挂起,有时需要重新启动。

但是与 VC 相比,现在有更多有用的类,例如 tcpclient,但这也意味着另一层重新学习,在标准套接字编程之上。有时我真的不喜欢这样。开发变得容易,但是技术的底层知识被掩盖了——就像我以 VB 开发人员的身份开始,尝试使用 VC 时一样,C/C++ 老鸟总是在交付时发出噪音,程序充满了不必要的行,并且不需要清理对象/类,这种习惯至今仍然跟着我。

© . All rights reserved.