473,320 Members | 1,946 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,320 software developers and data experts.

Walking away from UDP

Nak
Hi there,

After recently coming across issues with implementing a UDP server for
interprocess communication; involving file transfer, I have decided to go
onto TCP.

Now I *have* created a TCP server in the past for VB.NET but had
troubles when it comes to disconnecting all clients and cleaning up
remaining references. The problems arrise when using the IAsyncResult for
receiving data, once started a method is needed to successfully stop it at
*any* time.

I have looked back on past threads that I was involved in at the time
but still struggle to find the solution. As I understand it, I have to have
a public shared ManualResetEvent object for the client, as well as
implementing a state object to pass to the BeginRead method. But that is
about as much as I know, once I have a client connected to my server it
struggles to close correctly, as references are still "flying" about.

This is a brief outline of my current implementation...

Server)

* Contains a collection of client objects

1) A "start" method is called which contains a parameter for the
local port to listen on
2) A background thread is started which loops continuously calling
the "connect" method of a new client object and passing it the TCP listeners
AcceptTcpClient result.
3) Once a client connects its event handlers are initialized and it
is stored into the collection object. An event is then raised to notify the
main application that a client has just connected.

Client)

1) A "connect" method is called which contains an already initialized
TcpClient object which is to be passed by the server.
2) The TcpClients GetStream.BeginRead method is called and an
IAsyncResult object is created, this is stored in "module" level.
3) The TcpClients BeginRead async callback is raised when data is
recieved, if the data is 0 in length then the client is considered to be
disconnecting, otherwise an event is raised notifying the server of the
recieved data from the client and the BeginRead method is started again.

I have created a state object which contains 1 public property of
boolean type called "abortRequested" but I am unsure how to implement this.
If I create a public method called "close" for the client what should it
contain? Sorry for this long post but I am very eagre to get *a* method
working as I seem to be going around in circles! Thanks loads in advance!!!

Nick.
Nov 21 '05 #1
10 1962
Hi Nick,
1) A "connect" method is called which contains an already initializedTcpClient object which is to be passed by the server.

I am somewhat confused about the line above, why we need to pass the
TcpClient object from the server to the client?

In your scenario, it seems that we have the model as below.
Client Server
new TcpClient(A) -------------------------> TCPListener

|

|

----->TcpClient (B)
Then the A will communicate with B.
Here are two samples you may have a look.
Async TCP Socket Server
http://www.gotdotnet.com/Community/U...mpleGuid=d789d
245-4cf7-45af-9660-c375fc3f796c

Multi Threaded VB.NET TCP/IP Listener
http://www.gotdotnet.com/Community/U...mpleGuid=75e68
966-d567-47b3-a255-9a51f9cb0eb7

So far .NET framework did not support canceling an Asynchronous
Callback(i.e. the BeginRead and EndRead).
But we can set the read unit less, so that every time the BeginRead will
try to read the unit count of bytes from the networkstream.
e.g. (Just an example) we can set the value to 1, i.e. one byte per
BeginRead, then after EndRead call in the Asynchronous Callback(because
just one byte it will return quickly), then we can check a bool value to
see if we need to abort the read operation, if true, we can just close the
tcpclient and the Asynchronous Callback will exit, else we can keep read
the next byte.

If you still have any concern, please feel free to let me know.
Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 21 '05 #2
Nak
Hi Peter,

Excellent, I was hoping for your response as you seem to have allot of
knowledge on this subject.
So far .NET framework did not support canceling an Asynchronous
Callback(i.e. the BeginRead and EndRead).
But we can set the read unit less, so that every time the BeginRead will
try to read the unit count of bytes from the networkstream.
Wow! Now that suprises me, may I ask if you know what the underlying
mechanism is for BeginRead? Does it simply start a thread which constantly
checks the stream to seem how much data is in it, and when it reaches a
certain threshold the callback is fired?

Can this mechanism be simulated? Could I make my own BeginRead that can
be cancelled without any problems? Or would this require using the
"sockets" classes rather than TCPClient?
e.g. (Just an example) we can set the value to 1, i.e. one byte per
BeginRead, then after EndRead call in the Asynchronous Callback(because
just one byte it will return quickly), then we can check a bool value to
see if we need to abort the read operation, if true, we can just close the
tcpclient and the Asynchronous Callback will exit, else we can keep read
the next byte.


So the only way to cancel via this method would be to set the callback
to 1 byte and send a message to *yourself* to force the callback to be
invoked? Maybe even send a particular message to shut down the server, it
seems a pretty weird way of doing it but if it is the only way then I shall
have to. Surely other people have had this problem? How else would you
perform an asynchronous read on a socket without using the Asynchronous
callbacks?

Thanks for your help :-)

Nick.
Nov 21 '05 #3
Hi Nick,

BeginRead is kind of asynchronout callback. Usually we can consider it
similar as that we create a new thread and call the Read method in the
thread. After we call the BeginRead, the system will run a thread(From the
threadpool managed by system) to call the callback function in the thread
and EndRead was called to attempt to retrieve data back(just as we call the
Read, it will be blocked if no data arrived , so that the mainthread that
called the BeginRead will keep running. So the callback will be called
after we call the BeginRead, not after the data is arrived. Although we can
create a new thread and call the read method, and when we want to abort the
read operation, we can just abort the thread, but the method is not
recommended, because this may cause some resources not cleaned properly. A
better method is to let the thread exit itself, i.e. I have suggested
before read a few bytes everytime and evaluate a bool value to know if we
need exit the thread. In the last post I suggest one byte per time, that is
just a example, because if we read 1 MB per time, it will give us less
opportunity to cancel the read operation, because the 1 MB may take longer
time to complete reading than 1 byte. So the proper value should be decided
by your own according to the network connectivity status, bandwidth,
network adapt and so on. You may try to use the
myNetworkStream.DataAvailable to evaluate if the data is available, because
if myNetworkStream.DataAvailable is false, the EndRead will be blocked
until there is data arrived.

Here are the msdn documents for the three methods, you may try to compare
Read with BeginRead and EndRead,(Also there are example code in the links)
NetworkStream.Read Method
http://msdn.microsoft.com/library/de...us/cpref/html/
frlrfsystemnetsocketsnetworkstreamclassreadtopic.a sp
NetworkStream.EndRead
http://msdn.microsoft.com/library/de...us/cpref/html/
frlrfsystemnetsocketsnetworkstreamclassreadtopic.a sp
NetworkStream.BeginRead Method
http://msdn.microsoft.com/library/de...us/cpref/html/
frlrfsystemnetsocketsnetworkstreamclassreadtopic.a sp

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 21 '05 #4
Nak
Hi Peter,
... Although we can
create a new thread and call the read method, and when we want to abort the read operation, we can just abort the thread, but the method is not
recommended, because this may cause some resources not cleaned properly...
This is pretty much what is happening to me when I use BeginRead anyway,
the application just refuses to close correctly unless the connection has
been completely closed and disposed before hand. But if *no* data is being
sent and the connection hasn't been closed from the remote end then I have
issues.
better method is to let the thread exit itself, i.e. I have suggested
before read a few bytes everytime and evaluate a bool value to know if we
need exit the thread. In the last post I suggest one byte per time, that is just a example, because if we read 1 MB per time, it will give us less
opportunity to cancel the read operation, because the 1 MB may take longer
time to complete reading than 1 byte. So the proper value should be decided by your own according to the network connectivity status, bandwidth,
network adapt and so on.
Yeah this does sound like a good suggestion with 1 problem, if *no* data
is being sent anyway then the BeginRead call-back never fires, and the only
ways to make it fire is to send data or close the connection from the remote
end, which isn't always possible. But I see what you mean, it makes sense
to operate in this manor so that the connection can be closed much quicker.
Here are the msdn documents for the three methods, you may try to compare
Read with BeginRead and EndRead,(Also there are example code in the links)
NetworkStream.Read Method
http://msdn.microsoft.com/library/de...us/cpref/html/ frlrfsystemnetsocketsnetworkstreamclassreadtopic.a sp
NetworkStream.EndRead
http://msdn.microsoft.com/library/de...us/cpref/html/ frlrfsystemnetsocketsnetworkstreamclassreadtopic.a sp
NetworkStream.BeginRead Method
http://msdn.microsoft.com/library/de...us/cpref/html/ frlrfsystemnetsocketsnetworkstreamclassreadtopic.a sp


Thanks loads again, I shall read them intently!

Nick.
Nov 21 '05 #5
Hi Nick,

I look forward to your futher update, if you still have any concern on this
issue, please feel free to post here.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 21 '05 #6
Nak
Hi Peter,

I finally appear to have found a method that works successfully,

Private Sub startReading()
cTrdDownloadThread = New Threading.Thread(AddressOf doStartReading)
cTrdDownloadThread.IsBackground = True
Call cTrdDownloadThread.Start()
End Sub

Firstly a background thread is started to constantly check the network
stream

Private Sub doStartReading()
Dim pBytRxBuffer(READ_BUFFER_SIZE) As Byte
While (Not cBlnCancel)
Try
Dim pNStmStream As NetworkStream = cTCClient.GetStream
Dim pIntRxSize As Integer = pNStmStream.Read(pBytRxBuffer, 0,
READ_BUFFER_SIZE + 1)
If (pIntRxSize = 0) Then
cBlnCancel = True
RaiseEvent clientDisconnect(Me)
Else
If (pIntRxSize < (READ_BUFFER_SIZE + 1)) Then
Dim pBytRxBufferCrop(pIntRxSize - 1) As Byte
Call Array.Copy(pBytRxBuffer, pBytRxBufferCrop,
pIntRxSize)
RaiseEvent receivedData(Me, pBytRxBuffer)
Else
RaiseEvent receivedData(Me, pBytRxBuffer)
End If
End If
Catch ex As Exception
Call cTCClient.Close()
cBlnCancel = True
RaiseEvent clientDisconnect(Me)
End Try
End While
End Sub

The background thread constantly calls Read, thus blocking the thread
until data is recieved or the connection is closed. As it is a background
thread there is absolutly no problem with cancelling it, unlike an Async
Callback. The Try - Catch block is there as a precaution though the only
time I could think that it would be needed is during the NetworkStream read
method, if this were to raise an exception. I am not sure if the Close
method is needed in this block as I haven't actually seen any exceptions
raised, but none the less, the clients can now be disconnected when I
desire.

Thanks loads for your help Peter, its been a real insight.

Nick.

""Peter Huang"" <v-******@online.microsoft.com> wrote in message
news:ph**************@cpmsftngxa06.phx.gbl...
Hi Nick,

I look forward to your futher update, if you still have any concern on this issue, please feel free to post here.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 21 '05 #7
Nak
Hi there again!

I shall retract that previous statement, I have found yet more problems!

Take this for example,

When the Read method is called the thread is blocked, apparently the
only way to get around this is by checking DataAvailable. Now the problem
with DataAvailable is that it does *not* tell you if the connection has been
closed or not! The only way to know this is to call Read and have 0 bytes
returned to you, now isn't this bizaar?

So according the the Microsoft documentation the following should be
performed,

1. Check CanRead to prevent an IOException.
2. Check DataAvailable to prevent calling Read unnecessarily and blocking
the thread.
3. Call Read to return as much data as possible from the stream.

Problem # 1

CanRead remains True even if the remote end has disconnected. This
means you must call Read to check for a disconnection.

Problem # 2

DataAvailable will remain False during the event of a disconnection as 0
bytes are available! And a disconnection is detected by 0 bytes being
returned from the Read method.

Now this appears to be slightly strange to myself, I have a solution
that is slightly better than using BeginRead as I can cancel the thread at
any time and allow my program to close gracefully. But unfortunately this
results in an unreliable method of communication.

My question is this, is this the TCPClient at fault? If so, would using
"Sockets" help me or would I be in exactly the same situation? I never had
this problem with WinSock in VB6, I always found that to be quite reliable,
should I revert and make a .NET wrapper for it?

Hmmm, and much more hmmming besides...

Nick.

"Nak" <a@a.com> wrote in message
news:ux**************@TK2MSFTNGP11.phx.gbl...
Hi Peter,

I finally appear to have found a method that works successfully,

Private Sub startReading()
cTrdDownloadThread = New Threading.Thread(AddressOf doStartReading)
cTrdDownloadThread.IsBackground = True
Call cTrdDownloadThread.Start()
End Sub

Firstly a background thread is started to constantly check the network
stream

Private Sub doStartReading()
Dim pBytRxBuffer(READ_BUFFER_SIZE) As Byte
While (Not cBlnCancel)
Try
Dim pNStmStream As NetworkStream = cTCClient.GetStream
Dim pIntRxSize As Integer = pNStmStream.Read(pBytRxBuffer, 0,
READ_BUFFER_SIZE + 1)
If (pIntRxSize = 0) Then
cBlnCancel = True
RaiseEvent clientDisconnect(Me)
Else
If (pIntRxSize < (READ_BUFFER_SIZE + 1)) Then
Dim pBytRxBufferCrop(pIntRxSize - 1) As Byte
Call Array.Copy(pBytRxBuffer, pBytRxBufferCrop,
pIntRxSize)
RaiseEvent receivedData(Me, pBytRxBuffer)
Else
RaiseEvent receivedData(Me, pBytRxBuffer)
End If
End If
Catch ex As Exception
Call cTCClient.Close()
cBlnCancel = True
RaiseEvent clientDisconnect(Me)
End Try
End While
End Sub

The background thread constantly calls Read, thus blocking the thread
until data is recieved or the connection is closed. As it is a background
thread there is absolutly no problem with cancelling it, unlike an Async
Callback. The Try - Catch block is there as a precaution though the only
time I could think that it would be needed is during the NetworkStream read method, if this were to raise an exception. I am not sure if the Close
method is needed in this block as I haven't actually seen any exceptions
raised, but none the less, the clients can now be disconnected when I
desire.

Thanks loads for your help Peter, its been a real insight.

Nick.

""Peter Huang"" <v-******@online.microsoft.com> wrote in message
news:ph**************@cpmsftngxa06.phx.gbl...
Hi Nick,

I look forward to your futher update, if you still have any concern on

this
issue, please feel free to post here.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no

rights.


Nov 21 '05 #8
Nak
Hi yet again...

Deja vous?

Anyway, I *think* I have it this time, to successfully close the socket
when required and even have HyperTerminal pick up the disconnection, without
crashing the application and without leaving references open all over the
place. So this is what I have,

--------------------------------------
Private Sub startReading()
cTrdDownloadThread = New Threading.Thread(AddressOf doStartReading)
cTrdDownloadThread.IsBackground = True
Call cTrdDownloadThread.Start()
End Sub

Right, the above method is used for starting an asyncronous reading
process. Simple as that.
--------------------------------------
--------------------------------------
Private Sub doStartReading()
Dim pBytRxBuffer(READ_BUFFER_SIZE) As Byte
Do
Dim pIntRxSize As Integer
Try
pIntRxSize = cTCClient.GetStream.Read(pBytRxBuffer, 0,
READ_BUFFER_SIZE + 1)
Catch ex As Exception
pIntRxSize = 0
End Try

If (pIntRxSize = 0) Then
cBlnCancel = True
RaiseEvent clientDisconnect(Me)
Else
If (pIntRxSize < (READ_BUFFER_SIZE + 1)) Then
Dim pBytRxBufferCrop(pIntRxSize - 1) As Byte
Call Array.Copy(pBytRxBuffer, pBytRxBufferCrop, pIntRxSize)
RaiseEvent receivedData(Me, pBytRxBuffer)
Call Array.Clear(pBytRxBuffer, 0, READ_BUFFER_SIZE)
Else
RaiseEvent receivedData(Me, pBytRxBuffer)
End If
End If
Loop Until (cBlnCancel)
Call cleanUp()
End Sub

The Read method is encased in a try block to detect the stream being
shutdown locally and prevent nasty exceptions occuring. The number of bytes
recieved is set to 0, this kind of simulates a remote disconnection. Next
the number of bytes recieved is evaluated, if 0 the cancel flag is raised
and the clientDisconnect event is fired. If the client actually recieved
data then this is copied into an array and the array is passed back via the
receivedData event.

At the bottom cleanUp is called to remove references to the TcpClient
and Thread object.
--------------------------------------
--------------------------------------
Private Sub cleanUp()
cTrdDownloadThread = Nothing
cTCClient = Nothing
End Sub

The Cleanup method.
--------------------------------------
--------------------------------------
Public Sub cancel()
Call cTCClient.GetStream.Close()
End Sub

This is how the connection is closed locally, it forces an exception to
be raised @ the stream Read line in doStartReading. As simple as that.
--------------------------------------

Now I shall go and test yet more and probably come back saying this is a
heap of crap too! Who knows....

Nick.

Nov 21 '05 #9
Nak
All still works very very well!!!! :-D

Nick.

"Nak" <a@a.com> wrote in message
news:uE**************@TK2MSFTNGP10.phx.gbl...
Hi yet again...

Deja vous?

Anyway, I *think* I have it this time, to successfully close the socket when required and even have HyperTerminal pick up the disconnection, without crashing the application and without leaving references open all over the
place. So this is what I have,

--------------------------------------
Private Sub startReading()
cTrdDownloadThread = New Threading.Thread(AddressOf doStartReading)
cTrdDownloadThread.IsBackground = True
Call cTrdDownloadThread.Start()
End Sub

Right, the above method is used for starting an asyncronous reading
process. Simple as that.
--------------------------------------
--------------------------------------
Private Sub doStartReading()
Dim pBytRxBuffer(READ_BUFFER_SIZE) As Byte
Do
Dim pIntRxSize As Integer
Try
pIntRxSize = cTCClient.GetStream.Read(pBytRxBuffer, 0,
READ_BUFFER_SIZE + 1)
Catch ex As Exception
pIntRxSize = 0
End Try

If (pIntRxSize = 0) Then
cBlnCancel = True
RaiseEvent clientDisconnect(Me)
Else
If (pIntRxSize < (READ_BUFFER_SIZE + 1)) Then
Dim pBytRxBufferCrop(pIntRxSize - 1) As Byte
Call Array.Copy(pBytRxBuffer, pBytRxBufferCrop, pIntRxSize) RaiseEvent receivedData(Me, pBytRxBuffer)
Call Array.Clear(pBytRxBuffer, 0, READ_BUFFER_SIZE)
Else
RaiseEvent receivedData(Me, pBytRxBuffer)
End If
End If
Loop Until (cBlnCancel)
Call cleanUp()
End Sub

The Read method is encased in a try block to detect the stream being
shutdown locally and prevent nasty exceptions occuring. The number of bytes recieved is set to 0, this kind of simulates a remote disconnection. Next
the number of bytes recieved is evaluated, if 0 the cancel flag is raised
and the clientDisconnect event is fired. If the client actually recieved
data then this is copied into an array and the array is passed back via the receivedData event.

At the bottom cleanUp is called to remove references to the TcpClient
and Thread object.
--------------------------------------
--------------------------------------
Private Sub cleanUp()
cTrdDownloadThread = Nothing
cTCClient = Nothing
End Sub

The Cleanup method.
--------------------------------------
--------------------------------------
Public Sub cancel()
Call cTCClient.GetStream.Close()
End Sub

This is how the connection is closed locally, it forces an exception to be raised @ the stream Read line in doStartReading. As simple as that.
--------------------------------------

Now I shall go and test yet more and probably come back saying this is a heap of crap too! Who knows....

Nick.

Nov 21 '05 #10
Hi Nick,

If you still have any concern on this issue, please feel free to post here
and I will follow up.

Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.

Nov 21 '05 #11

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Who Cares | last post by:
Okay, this may be a bit of a newbie question but I could really use some help. I want to write a set of routines that will read in the contents of XML files. I'll be reading the tag names,...
0
by: Chris Lyon | last post by:
I handle a lot of audio files of different formats, which live in a directory tree. WAV files in a wav directory, AIFF's in an AIFF directory next to the wav directory and mp3's in an MP3 directory...
4
by: Jim Bancroft | last post by:
Sorry for the basic nature of this question. I know XSL can do this, but I don't recall a good method... Say I have an xml structure like this: <folder_structure> <folder name="folder1">...
15
by: Trevor Lango | last post by:
I want to be able to cast away the constness of a private member variable in a member function of a class. I have the private data member declared as follows: const double x; I have an...
1
by: Zachary Hartnett | last post by:
I was trying to write a routine this morning that would open a given assembly, walk the inheritance tree of classes in the assembly, and provide a list of classes in the assembly that inherit from...
5
by: Patrick Vanden Driessche | last post by:
Hi All, I'm currently writing an in-house Form validation framework (WinForms) which is based on 'Component'-inheriting object. So basically, I have a small hierarchy. FormValidator +--...
5
by: TrulyUnusualdotcom | last post by:
I'm reading PHP & MySQL for Dummies 2nd edition...ya ya I know..lame. Anyway I got to the part about walking through an array and I just can't seem to figure out what this would be used for. What...
8
by: Ben Hallert | last post by:
Hi guys! I'm working on a little javascriptlet/greasemonkey script, and I've run into a challenge that I think can be solved with walking the DOM, but I feel like I'm kludging my way through and...
2
by: Evan Carmi | last post by:
hi, i am creating a program to go through a directory structure recursively (including directories below it) and move all files that end in .msf to a directory above the current level. the...
11
by: Simon Woods | last post by:
Hi I have this recursive function and I want to walk the inheritance hierarchy to set field values .... the generic T is constrainted as the base class of the inheritance hierarchy Friend...
0
by: DolphinDB | last post by:
The formulas of 101 quantitative trading alphas used by WorldQuant were presented in the paper 101 Formulaic Alphas. However, some formulas are complex, leading to challenges in calculation. Take...
0
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
1
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 6 Mar 2024 starting at 18:00 UK time (6PM UTC) and finishing at about 19:15 (7.15PM). In this month's session, we are pleased to welcome back...
0
by: Vimpel783 | last post by:
Hello! Guys, I found this code on the Internet, but I need to modify it a little. It works well, the problem is this: Data is sent from only one cell, in this case B5, but it is necessary that data...
0
by: ArrayDB | last post by:
The error message I've encountered is; ERROR:root:Error generating model response: exception: access violation writing 0x0000000000005140, which seems to be indicative of an access violation...
1
by: PapaRatzi | last post by:
Hello, I am teaching myself MS Access forms design and Visual Basic. I've created a table to capture a list of Top 30 singles and forms to capture new entries. The final step is a form (unbound)...
0
by: Shællîpôpï 09 | last post by:
If u are using a keypad phone, how do u turn on JavaScript, to access features like WhatsApp, Facebook, Instagram....
0
by: af34tf | last post by:
Hi Guys, I have a domain whose name is BytesLimited.com, and I want to sell it. Does anyone know about platforms that allow me to list my domain in auction for free. Thank you
0
by: Faith0G | last post by:
I am starting a new it consulting business and it's been a while since I setup a new website. Is wordpress still the best web based software for hosting a 5 page website? The webpages will be...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.