Async socket connection ends up in Unable to read data from....

A

Arno

reposted with the right microsoft managed newsgroup ID: Sorry for the
inconvinience

Hi,

I've written a class for client-socket connection, but I get a lot of times
the error message "Unable to read data from the transport connection" when
restart reading the stream with socket.BeginRead in the Sub
SocketIncomingMsg. I'm debugging now for weeks, but I can't detect where
it's
going wrong.

the part of code where it fails:

Try
RnetworkStream.BeginRead(myReceivedData, 0,
myReceivedData.Length, New AsyncCallback(AddressOf SocketIncomingMsg),
RnetworkStream)
Catch ex As Exception
'THIS ONE OFTEN FAILES
'UNABLE TO READ DATA FROM THE TRANSPORT CONNECTION
DisconnectSocket()
End Try

Can someone please review my code and point me in the right direction. This
thing is driving me nuts..

The Complete code:

Imports System.Net.Sockets
Imports System.Text
Imports System.Threading

Namespace TCPIP
Public Enum Status
Disconnected = 0
Listening = 1
Connected = 3
Connecting = 2
End Enum

Public Class TCPClientSock
Private mState As TCPIP.Status
Private mTcpClient As TcpClient
Private RnetworkStream As NetworkStream

Public Event DataReceived(ByVal Data As String)
Public Event CommError(ByVal ErrorMessage As Exception)
Public Event StatusChanged(ByVal State As TCPIP.Status)

Private myReceivedData() As Byte

Public Sub New()
mState = TCPIP.Status.Disconnected
RaiseEvent StatusChanged(mState)
End Sub
Public ReadOnly Property Connected() As Boolean
Get
Return (mState = Status.Connected)
End Get
End Property
Public Sub Shutdown()
Me.DisconnectSocket()
End Sub
Public Function ConnectSocket(ByVal Server As String, ByVal Port As
Int16) As Boolean
Try
mTcpClient = Nothing
mTcpClient = New TcpClient
'make connection
mState = TCPIP.Status.Connecting
RaiseEvent StatusChanged(mState)
mTcpClient.Connect(Server, Port)
'connected
RnetworkStream = mTcpClient.GetStream
If RnetworkStream.CanRead Then
mState = TCPIP.Status.Connected
ReDim myReceivedData(mTcpClient.ReceiveBufferSize)
'start reading stream
RnetworkStream.BeginRead(myReceivedData, 0,
myReceivedData.Length, New AsyncCallback(AddressOf SocketIncomingMsg),
RnetworkStream)
RaiseEvent StatusChanged(mState)
Return True
End If
Catch e As Exception ' error while connecting
RaiseEvent CommError(e)
'not connected
mState = TCPIP.Status.Disconnected
RaiseEvent StatusChanged(mState)
Try
mTcpClient.Close()
Catch
End Try
End Try
End Function

Private Sub SocketIncomingMsg(ByVal arMsg As IAsyncResult)
Dim intCount As Integer
Dim lus As Int16
Dim myMessage As String = ""
Try
intCount = RnetworkStream.EndRead(arMsg)
If intCount < 1 Then
'socket closed
DisconnectSocket()
End If
Catch ex As Exception

End Try
For lus = 0 To intCount - 1
myMessage &= Chr(myReceivedData(lus))
Next
'process message in background
ThreadPool.QueueUserWorkItem(AddressOf Me.ProcessReceivedData,
CType(myMessage, Object))
'restart reading stream
Try
RnetworkStream.BeginRead(myReceivedData, 0,
myReceivedData.Length, New AsyncCallback(AddressOf SocketIncomingMsg),
RnetworkStream)
Catch ex As Exception
'THIS ONE OFTEN FAILES
'UNABLE TO READ DATA FROM THE TRANSPORT CONNECTION
DisconnectSocket()
End Try
End Sub

Private Sub ProcessReceivedData(ByVal Data As Object)
If CStr(Data) <> "" Then RaiseEvent DataReceived(CStr(Data))
End Sub

Public Sub DisconnectSocket()
Try
RnetworkStream.Close()
Catch ex As Exception
End Try
Try
mTcpClient.Close()
Catch ex As Exception
End Try
Try
mTcpClient = Nothing
Catch ex As Exception
End Try
mState = TCPIP.Status.Disconnected
RaiseEvent StatusChanged(mState)
End Sub

Public Sub SendSocketData(ByVal Data As String)
Try
Dim SnetworkStream As NetworkStream = mTcpClient.GetStream()
Dim sendBytes(Data.Length - 1) As Byte
Dim lus As Int16
For lus = 0 To Data.Length - 1
sendBytes(lus) = Asc(Data.Substring(lus, 1))
Next
SnetworkStream.Write(sendBytes, 0, sendBytes.Length)
Catch e As Exception
RaiseEvent CommError(e)
End Try
End Sub
End Class
Public Class TCPServerSock
'removed due to irrelevance
End Class
End Namespace
 
P

Peter Huang [MSFT]

Hi,

From your description, when you use the the code you provided in your
application, the code that below will generate the error as below.
"Unable to read data from the transport connection"

The occurred when the SocketIncomingMsg method is reentry after the first
reading operating finished.

Here is the make a simple test for your code, but I can not reproduce the
problem.
[Server]
Imports System
Imports System.Net.Sockets
Imports System.Text

Public Class TcpTimeServer

Private Const portNum As Integer = 13

Public Overloads Shared Function Main(ByVal args() As [String]) As
Integer
Dim done As Boolean = False

Dim listener As New TcpListener(portNum)

listener.Start()

While Not done
Console.Write("Waiting for connection...")
Dim client As TcpClient = listener.AcceptTcpClient()

Console.WriteLine("Connection accepted.")
Dim ns As NetworkStream = client.GetStream()

Dim byteTime As Byte() = _
Encoding.ASCII.GetBytes(DateTime.Now.ToString())

Try
ns.Write(byteTime, 0, byteTime.Length / 2)
System.Threading.Thread.Sleep(3000)
ns.Write(byteTime, byteTime.Length / 2, byteTime.Length / 2)
ns.Close()
client.Close()
Catch e As Exception
Console.WriteLine(e.ToString())
End Try
End While

listener.Stop()

Return 0
End Function 'Main
End Class 'TcpTimeServer

[Client]
Public Class Form1
Dim WithEvents c As TCPIP.TCPClientSock

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
c = New TCPIP.TCPClientSock()
If c.ConnectSocket("machinename", 13) Then
MsgBox("Connected")
End If
End Sub

Private Sub c_DataReceived(ByVal Data As String) Handles c.DataReceived
MsgBox(Data)
End Sub
End Class

You may have a try and let me know if the code above will reproduce the
problem at your side.

I look forward to hearing from you.

Also I suggest try to check the RnetworkStream.CanRead in method
SocketIncomingMsg, just as you do in the method ConnectSocket.


Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
A

Arno

Peter,

the code you send me works just fine..

To clear out more specific on my problem, The error doesn't occur after the
first read operation is finished, as far as I can see, it's completely
random (it should have a reason, but I can't track it down) Sometimes it's
after the 4th read operation, sometimes it's after the 500th read operation,
sometime it's after the ... read operation. In other words, sometimes it
fails after 5 minutes, sometimes after 1 hour, sometimes after 1 day.

In my application, the socket-connection stays connected 24/7 (it least it
should do so), at least every 15 minutes I will receive some data from the
server, sometimes less as 15 minutes.

The socket connection will use a gprs connection to the server, so some
small latency can occur, but i think the OS should take care of this... (Is
this right?)

What reason can there be that this error occurs when

RnetworkStream.BeginRead(myReceivedData, 0, myReceivedData.Length, New
AsyncCallbackAddressOf SocketIncomingMsg),RnetworkStream)

Is it possible that a networkstream 'suddenly' becomes 'unreadable' so that
I have to check RnetworkStream.CanRead every time when doing the .BeginRead?

What to do when .CanRead = False, can the stream become readable again after
some time? I don't want to reconnect my socket everytime to the server
again. If it can recover, how to do so.

On the server-side, the socket is still connected when the client fails the
..BeginRead

This thing is driving me nuts....

Kind regards,


Arno Broeders
 
P

Peter Huang [MSFT]

Hi Arno,

It is hard to guess what is the root cause the scenario without reproduce
the problem.
From the description, I understand the Exception throw is IOException.

But from the MSDN doucment in the scenario below, the IOException may be
thrown when the NetworkStream.BeginRead
IOException
The underlying Socket is closed.
-or-
There was a failure while reading from the network.
-or-
An error occurred when accessing the socket. See the Remarks section for
more information.

Note
If you receive an IOException, check the InnerException property to
determine if it was caused by a SocketException. If so, use the ErrorCode
property to obtain the specific error code, and refer to the Windows
Sockets version 2 API error code documentation in MSDN for a detailed
description of the error.

NetworkStream.BeginRead Method
http://msdn2.microsoft.com/en-us/library/system.net.sockets.networkstream.be
ginread.aspx

So I think you may try to print out the detailed Exception/InnerException
information as below.
Try
Catch ex As Exception
Debug.Print(ex.ToString())
Debug.Print(ex.InnerException.ToString())
DisconnectSocket()
End Try
Also please check all the code in both Server and Client about close
socket/connection.
Because you can not reproduce the problem with my server code, you may try
to add Log code line before every socket related call.
e.g.
Debug.Print "Socket accept"
Debug.Print "Socket read"
Debug.Print "Socket close"

To monitor if there is any possibility that the socket is closed by server
side.

Here is the error list may occur in the Win32 ErrorCode.
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/win
sock/recv_2.asp
or
the path to the C++ header Winsock2.h
e.g.<this may differ based on your installation>
C:\Program Files\Microsoft Platform SDK for Windows Server 2003 R2\Include

Best regards,

Peter Huang

Microsoft Online Community Support
==================================================
When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
==================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 
A

Arno

Okay, I implemented the logging in my application and found 2 reasons for
errors.

14-9-2006 10:18:14 - System.IO.IOException: Unable to read data from the
transport connection. ---> System.Net.Sockets.SocketException: An existing
connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.BeginReceive(Byte[] buffer, Int32 offset,
Int32 size, SocketFlags socketFlags, AsyncCallback callback, Object state)
at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32
offset, Int32 size, AsyncCallback callback, Object state)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32
offset, Int32 size, AsyncCallback callback, Object state)
at
DataCollectorService.TCPIP.TCPClientSock.SocketIncomingMsg(IAsyncResult
arMsg) in
S:\VS.2003\Projects\iView\PartialCollectors\OMRON-Collector\ClsTCPIP.vb:line
86
14-9-2006 10:18:14 - System.Net.Sockets.SocketException: An existing
connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.BeginReceive(Byte[] buffer, Int32 offset,
Int32 size, SocketFlags socketFlags, AsyncCallback callback, Object state)
at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32
offset, Int32 size, AsyncCallback callback, Object state)

This one is strange because the socket on the server was still opened. Maybe
it's my 3com internet NAT-router that will close socket connections that
stay open for a long time. Can this be?

Second error is:

14-9-2006 9:35:22 - System.ObjectDisposedException: Cannot access a disposed
object named "System.Net.Sockets.NetworkStream".
Object name: "System.Net.Sockets.NetworkStream".
at System.Net.Sockets.NetworkStream.BeginRead(Byte[] buffer, Int32
offset, Int32 size, AsyncCallback callback, Object state)
at
DataCollectorService.TCPIP.TCPClientSock.SocketIncomingMsg(IAsyncResult
arMsg) in
S:\VS.2003\Projects\iView\PartialCollectors\OMRON-Collector\ClsTCPIP.vb:line
86

This one is bugging me the most.. How can it be that .EndRead on the stream
is succesfull and when doing a new .BeginRead the stream is suddenly
disposed.

Peter can you please advise me?

Kind regards,


Arno
 
P

Peter Huang [MSFT]

Hi Arno,

Thanks very much for your efforts and information.

From your information, you will encounter two exceptions.
1. System.IO.IOException: Unable to read data from the transport
connection. ---> System.Net.Sockets.SocketException: An existing connection
was forcibly closed by the remote host

As the error description, this means the underlying socket is closed by
remote host. But due to the complex in network environment this may be
caused by many possibility. Your assumption also may be one of the
possibility. Because the network path between your machine A and the Server
B may include many other network devices, e.g. Router, Proxy, Firewall.....

2. System.ObjectDisposedException: Cannot access a disposed
object named "System.Net.Sockets.NetworkStream".

From the error, the networkstream is disposed. But we are still trying to
access to it. So far it is hard to guess what is the root cause. A possible
cause it that after the End Read, the underlying socket may be closed, so
the networkstream is disposed too and then we are trying to access it so
get the exception.

Since so far you can not reproduce the problem with the simple server code
I send to you.

I suggest you try to run your Server and Client code on two directly
connect machines or even one machine, if there are no error occur for a
long time e.g. one week. We should consider your code is OK but is not
robust and error handling enough.

Commonly network application will need more error handling than common
application, especially the wireless network environment. A common way is
to handle all the possible exception and do proper action, so that we can
built a robust application.
BTW: for such GRPS network, I understand it is low bandwidth network and
not very relialbe(it may be disconnected due to gprs signals) compared to
LAN, I suggest you sent a small data in one time so that a End Read will
finish more quick.
e.g.
If the socket is closed, we may try to reconnect to the server and try a
predefined time to write error log. This depends on concrete implement
policy.
The main idea is to retry when error occurred, and retry a few times to
reconnect or event report error to End User and stop doing.
Just as IE, when we are trying to connect to a web site, when it has gone
through its error handle steps, it will show an error page to End User.

If you still have any concern, please feel free to let me know.
I look forward to hearing from you.

Best regards,

Peter Huang
Microsoft Online Partner Support

When responding to posts, please "Reply to Group" via your newsreader so
that others may learn and benefit from your issue.
=====================================================
Business-Critical Phone Support (BCPS) provides you with technical phone
support at no charge during critical LAN outages or "business down"
situations. This benefit is available 24 hours a day, 7 days a week to all
Microsoft technology partners in the United States and Canada.


This and other support options are available here:
BCPS:
https://partner.microsoft.com/US/technicalsupport/supportoverview/40010469
Others: https://partner.microsoft.com/US/technicalsupport/supportoverview/

If you are outside the United States, please visit our International
Support page: http://support.microsoft.com/common/international.aspx.
=====================================================
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top