RSH
RSH

Reputation: 395

First TCP response receiving 0 bytes but according to netmon there are responses after that

I have a situation where I am sending the correct request bytes to a machine. When run through another application I can see that the response is sent, the machine sends a first response that contains no bytes (only header data) so in my code I am checking if "tcpStream.DataAvailable" it obviously returns "false" then the program exits.

The problem is that first response is not where the data is...it is in several following responses.

So basically how do I ignore the first response and wait for the data in the 2+ responses?

This is the snippet of code I am using:

byte[] myReadBuffer = new byte[1024];
StringBuilder myCompleteMessage = new StringBuilder();
int numberOfBytesRead = 0;

// Incoming message may be larger than the buffer size. 
do
{
    numberOfBytesRead = tcpStream.Read(myReadBuffer, 0, myReadBuffer.Length);
    myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
}
while (tcpStream.DataAvailable);

UPDATE:

I changed the code to asynchronously handle the communication. This is the new code (still doesn't work):

 public class GetCellList
{ 
    private ManualResetEvent connectDone = new ManualResetEvent(false);
    private ManualResetEvent sendDone = new ManualResetEvent(false);
    private ManualResetEvent receiveDone = new ManualResetEvent(false);

    private string _serverIP;
    private int _serverPort;
    private StateObject _stateObject = new StateObject();

    private static String response = String.Empty;

    public GetCellList(string serverIP, int serverPort)
    {
        _serverIP = serverIP;
        _serverPort = serverPort;
        _stateObject.workSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(_serverIP), _serverPort);
        StartClient(remoteEP);
    }


    private void StartClient(IPEndPoint remoteEndpoint)
    { 
        try
        { 
            _stateObject.workSocket.BeginConnect(remoteEndpoint,
                    new AsyncCallback(ConnectCallback), _stateObject.workSocket);
            connectDone.WaitOne();

            Send(_stateObject.workSocket, GetData());
            sendDone.WaitOne();

            Receive(_stateObject.workSocket);
            receiveDone.WaitOne();

            Console.WriteLine("Response received : {0}", response);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private byte[] GetData()
    {
        var requestString = "00 25 B4 CE 42 80 D4 81 D7 DD 44 37 08 00 45 00 00 43 06 27 00 00 80 06 00 00 0A D4 E2 4E 0A 68 3D CC 2E 12 04 01 4B 7A C8 7B FE 5C 2E F5 50 18 00 FF 35 8C 00 00 43 50 43 52 00 01 19 00 00 00 1B 00 00 00 02 00 00 00 00 00 00 00 1D 00 00 00 00".Replace(" ", "");

        return Convertors.ConvertToByteArray(requestString);

    }

    private void ConnectCallback(IAsyncResult ar)
    {
        try
        { 
            Socket client = (Socket)ar.AsyncState;

            client.EndConnect(ar);

            Console.WriteLine("Socket connected to {0}",
                client.RemoteEndPoint.ToString());

            connectDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private void Receive(Socket client)
    {
        try
        { 
            StateObject state = new StateObject();
            state.workSocket = client;

            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(ReceiveCallback), state);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;

            int bytesRead = client.EndReceive(ar);

            if (bytesRead > 0)
            { 
                state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));

                client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(ReceiveCallback), state);
            }
            else
            {

                if (state.sb.Length > 1)
                {
                    response = state.sb.ToString();
                }

                receiveDone.Set();
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private void Send(Socket client, byte[] byteData)
    { 
        client.BeginSend(byteData, 0, byteData.Length, 0,
            new AsyncCallback(SendCallback), client);
    }

    private void SendCallback(IAsyncResult ar)
    {
        try
        {
            Socket client = (Socket)ar.AsyncState;

            int bytesSent = client.EndSend(ar);
            Console.WriteLine("Sent {0} bytes to server.", bytesSent);


            sendDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }
}

}

Upvotes: 1

Views: 587

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062955

The problem here is exactly that you're checking for tcpStream.DataAvailable. This is the amount of data buffered locally, and it being zero tells you nothing about what is about to arrive. The more typical loop would be:

while((numberOfBytesRead = tcpStream.Read(myReadBuffer, 0, myReadBuffer.Length)) > 0)
{ ... }

The only real use for DataAvailable is deciding whether to read synchronously or asynchronously - you might choose to read asynchronously if there's nothing in the buffer.

Note that in general you should also be very careful about "framing" and knowing whether what you have in the buffer can be sensibly processed; you just about get away with it in your case since you're using ASCII, but if this was something like UTF8 you'd need to be much more careful, as a single character might span two (or more, in theory) Read calls - meaning you might get one byte of a 3-byte character at the end of the buffer, and the other two bytes of that same character at the start of the buffer in the next Read call.

Upvotes: 2

Related Questions