Introduction
This is a project that I'd initiated as a messaging
platform for communication. MSN protocol is one of the channels chosen, for its
"always up and Internet available" feature.
MSN protocol based messaging is just as any other TCP based
client program, it means Winsock programming. With asynchronous processing
we will make the program response much better. I'm looking more than
this, the program should fork its own thread for each individual MSN ID that is
online, so that it can broadcast messages using individual channels. Thus it
needs multithreaded processing capability.
I've developed this under VB.Net as .Net had provided handy classes that ease
these jobs. Comparing the day of only VC having the strong support for these
requirements, I'm still remembering the
multithreaded socket based server module that I had developed. But then
I've encountered a diff problem.
There are 3 major challenges I've encountered during
the development
- MSN Protocol communication
- MD5 hashing under VB.Net
- Multithreading an asynchronous processing TCP Client
Using the code
MSN Protocol communication
- There are several sites that maintained information on MSN
protocol. MSN Messenger
Protocol surely is an interesting site that should not be missed.
- Frankly, I've problems in getting the correct
sequence to work under VB.Net, especially on the logon to the server.
Until I encountered another project file on CodeProject site that
demonstrate the MSN connection – Connecting to
MSN
- I've got that to work under VB.Net plus the MSN
challenge handling
MD5 Hashing
After the MSN logon, it will receive the challenge key a
short while later, we'll need to response back the key, by MD5
hashing the key, plus the original key, in order to keep online. Current
version will wait until the challenge acknowledged by the MSN server, then
multiple thread will fork for each of the online MSN ID, sending them
message.
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
Asynchronous with Multithread
This is the most challenging part. The code work correct as a single thread.
After this point of calling the BeginRead
, any next incoming data received via
TcpClient
will be response to the AsyncCallBack
via
SocketIncomingMsg
. The
EndRead
will captur the incoming data in Byte stream.
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
When I initiated the asynchronous by just triggered the sub routine
module (sample: btnTestCon click
event). Everything turned out fine.
Start_MSN()
When I've called this via forking another thread to handle, it will fail to read the data from
TCPClient
, the EndRead
will only return an error.
Error such as “Unable to read data from the transport connection.”
The same goes with the section that forked multiple threads, each for one
online MSN ID. They all failed at the same point.
Dim MSNThread As Threading.Thread = New Threading.Thread(AddressOf Start_MSN)
MSNThread.Start()
I've attempt to catch the exception, and following the MSDN
documentation, the inner exception too. But the message are not much helpful,
(what is error 995 ??)
Catch e As Exception
LogToFile(e.InnerException.ToString())
Exception Output:
Many other attempts had I tried, but none successes. Finally I focus on
the EndRead
, does this have something to do with asynchronous under multithread
environment? So I called the synchronous processing after the BeginRead
.
readCallBack = New AsyncCallback(AddressOf SocketIncomingMsg)
Dim iarReturn As IAsyncResult = tcpClient.GetStream.BeginRead(bytDataRead, _
0, 1024, readCallBack, tcpClient.GetStream)
iarReturn.AsyncWaitHandle.WaitOne()
It works!!!
Points of Interest
Comparing the previous version of VB, multithread programming under VB.Net
is surely more stable, between the debugging and pausing, the development
toolkit does not undergo sudden hang, where sometimes a reboot is needed.
But comparing the VC, there is more helpful class now, such as tcpclient,
but then this also spelled another layer of re-learning, on top of the standard
socket programming. Sometimes I really do not enjoy this. Development is made easy, but the base know-how of the tech is cover up – much like those
days I started as VB developer, attempt with VC, the C/C++ old bird always
making noise on the delivery, the programs are full of unnecessary lines, and no
clean up of objects/class required, a habit that still follows me even now.