attn:MVPs

S

Slappy White

Hi All,
I have a strange problem with .net sockets (Protocol TCP/IP). I have
developed a slave application that listens for incoming connection in
asynchronous mode, and accepts incoming connection in a socket and returns
to the listening mode.

The connected socket then uses async mode to read and write from the
underlying network stream. In the AsyncRead call back function an event is
raised to handle the data received. While processing the message, If the
break the connection from my master application (which sends data), none of
the async read/send call back methods throws an exception to indicate
connection is broken.

The worst is when I send the Ack, the properties of socket indicate the
stream is connected and the async send method sends data without any
throwing exception. But, I know for sure connection is broken. This puts my
messaging processing system in soup.

The big issue for me here is that I have invested a great deal of time and
an important client's money developing this solution. I chose .Net because
of it's reputation as a cutting edge server based framework and convinced my
client this was the way to go. Now I find that the solution is unusable and
I have been let down by the .Net framework. This is a critical system and a
socket sending an acknowledgement to a non-existent connection and reporting
success is frightening in terms of the undependability of this component of
the .Net Framework.

Is there an answer to this problem? Is there a fix for what is undeniably a
massive bug in the Socket class? How can I proceed using my solution in
..Net?

Is there an alternative third party socket class (similar to winsock
control) that I can use to solve this problem?

Any help is greatly appreciated.

Thanks & Regards,
An extremely disappointed dotnet framework user.
 
J

John Saunders

I don't have a very detailed answer for you, since I haven't used .NET
socket stuff in a while. But I have a suggestion from my general TCP/IP
experience.

You should not assume that you are going to get any indication of a broken
connection. In particular, you are unlikely to receive such an indication on
a "send" operation - it's more likely to come during a "receive".

Also, you seem to want to use the existence of a broken connection as part
of your protocol (you said that the lack of an indication messed up your
logic). This is a bad idea. If you need an indication that the other side is
there, then you need to send it a message requiring a response. A timeout in
the response will tell you the other side isn't all there (and you can retry
if you like and if the connection is still open). If you get the response,
you know the other side is there.

Keep in mind that the TCP/IP protocol doesn't maintain message boundaries -
a what is sent as a 1024 byte message might be received a byte at a time. By
the same token, not all indications will arrive in sync.
 
J

Jason

if you drop some reproducible code here it would be easier to help you as i
don't always have the time to knock out an example
 
S

Slappy White

Hi Jason,
Thanks for your kind note and sorry for my long silence. .NET
SOCKETS/FRAMEWORK LACK THE CAPABILITY of propogating the error up from the
winsock dll to the managed .net environment.

1. I have an asynchronous TCP socket (Say, slave) that listens for data from
a Master (which I don't have any control).

Design Constraints:
The Slave should not initiate any connection requests/ send other messages
EXCEPT the acknowledgement for the incoming messages from master, at all
times. And the slave should not look for any response from the master for
the acknowledgement it sends.



The Master polls for the connection and I accept connection in a thread
like,

// Create a new TCPListner Slave and start it up
m_pTcpListener = new
TcpListener(Dns.Resolve(IpAddress).AddressList[0],Port);
m_pTcpListener.Start();


Socket pClientSocket = null;
// Inside the thread loop - If a client connects, accept the connection
pClientSocket = m_pTcpListener.AcceptSocket();


*The incoming connection is accepted and the listener keeps listening for
incoming connection in its thread.
Accepting Connection, Receiving Data all works fine. Here are the methods
for receiving data,

/// <summary> Wait for a message to arrive </summary>
public void Receive()
{
if ((m_pNetworkStream != null) && (m_pNetworkStream.CanRead))
{
// Issue an asynchronous read
m_pNetworkStream.BeginRead(m_bytRawBuffer, 0, m_iSizeOfRawBuffer,
m_pCallbackReadMethod, null);
}
else
throw new Exception("Socket Closed");
}

/// <summary>Called when a message arrives</summary>
/// <param name="ar">An async result interface</param>
private void ReceiveComplete(IAsyncResult ar)
{
try
{
// Is the Network Stream object valid
if (m_pNetworkStream.CanRead)
{
// Read the current bytes from the stream buffer
int iBytesRecieved = m_pNetworkStream.EndRead(ar);
// If there are bytes to process else the connection is lost
if (iBytesRecieved > 0)
{
try
{
string RawData =
System.Text.Encoding.ASCII.GetString(m_bytRawBuffer,0,iBytesRecieved);

// A message came in send it to the MessageHandler
this.SocketStateHandler(SocketStatus.DataReceived,RawData);
}
catch
{
}
// Wait for a new message
Receive();
}
else
throw new Exception("Shut Down");
}
}
catch (Exception ex)
{
try
{
// The connection must have dropped call the CloseHandler
this.SocketStateHandler(SocketStatus.ConnectionBroken,ex.Message);
}
catch
{
}
// Dispose of the class
Dispose();
}
}

*After parsing data, Acknowledgement message need to be sent to the Master.
I put a break point in the start of the send method and shutdown my Master
application completely to ensure it does not exist. Then, if I run through
the code, the send method sends the acknowledgement without throwing any
exception as if the connection exists and everything is fine. This is a
potential bug in the .net sockets framework.

/// <summary>Send a raw buffer to the server</summary>
/// <param name="pRawBuffer">A Raw buffer of bytes to send</param>
public void Send(Byte[] pRawBuffer)
{
if ((m_pNetworkStream != null) && (m_pNetworkStream.CanWrite))
{
// Issue an asynchronus write
m_pNetworkStream.BeginWrite(pRawBuffer, 0, pRawBuffer.GetLength(0),
m_pCallbackWriteMethod, null);

}
else
throw new Exception("Socket Closed");
}


/// <summary>Called when a message is sent</summary>
/// <param name="ar">n async result interface</param>
private void SendComplete(IAsyncResult ar)
{
try
{
// Is the Network Stream object valid
if (m_pNetworkStream.CanWrite)
m_pNetworkStream.EndWrite(ar);
}
catch (Exception ex)
{
//Connection Error
this.SocketStateHandler(SocketStatus.ConnectionBroken,ex.Message);
}
}


*Nowhere exception is thrown and how to sovle this?



2. A VB6 application downloaded from the internet uses winsock's "Select"
function to ensure the socket is readable and it works fine in conjunction
with the master application. It detects immediately when I break the
connection/close the master application. So, I tried making a direct call to
"select" function of winsock dll as follows, (unfortunately it did not work
in the .net)


[DllImport("ws2_32.dll", CharSet=CharSet.Ansi, SetLastError=true)]
internal static extern int select([In] int ignoredParameter, [In] out fd_set
readfds, [In] out fd_set writefds, [In] out fd_set exceptfds, [In] IntPtr
nullTimeout);


[StructLayout(LayoutKind.Sequential)]
public struct fd_set
{
public int fd_count;
public int[] fd_array; //array of sockets
}



//make a call with sockets
fd_set SocWrite = new fd_set();
SocWrite.fd_count = 1;
SocWrite.fd_array[1] = socket.handle; //Inptr socket.handle property.
int i =
select(System.IntPtr.Zero,SockRead,SocWrite,SockError,System.IntPtr.Zero);


* Even this is not working but the call to "select" works within the VB6
Application. Am I doing something wrong here?



3. The final option Iam going to try is make an VB6 dll and try to call that
dll from .net. But I dont know how to get the long handle required by the VB
call to the dll.

Please throw some light and help me to get out of this problem.

Thanks & Regards,
Senthil.
 

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