简体   繁体   中英

C# TCP client read occasionally receives no data - 'nothing'

I have written a TCP client which communicates with a server. In a dedicated 'listening' thread, I have the code as below. It should only read data when there is some data there. ( if (stream.DataAvailable) )

Oddly, occasionally my program will crash because the stream will read absolutely no data. It will return an empty string . Even more oddly, if I try and 'catch' an empty string in the handleResponse(string s) function, it doesn't get caught.

    public void listenForResponses()
    {
        Console.WriteLine ("Listening...");
        while (isConnected == true)
        {
            Thread.Sleep (updateRate);
            String responseData = String.Empty;

            if (stream.DataAvailable) {
                Int32 bytes = stream.Read (data, 0, data.Length);
                Console.WriteLine (" >> Data size = "+data.Length);
                responseData = System.Text.Encoding.ASCII.GetString (data, 0, bytes);
                output = responseData+"";
                handleResponse (output);
            }
            if (isConnected == false) {
                closeConnection ();
            }
        }
    }

public void handleResponse(string msg)
{
    Console.WriteLine ("Received: "+msg); 
    iterateThroughEachCharInString (msg);
    if ((msg != "")&&(msg != null)&&(msg != " ")) {
        JSONDataObject desrlzdResp = JsonConvert.DeserializeObject<JSONDataObject>(msg);

        if ((desrlzdResp.instruction != null)) {
            if (desrlzdResp.instruction == "TestConn") {
                handleTestConn (desrlzdResp);
            } else if (desrlzdResp.instruction == "SceneOver") {
                handleSceneFinished (desrlzdResp);
            }
        }
    }
}

The exception thrown is System.NullReferenceException on the line if ((desrlzdResp.instruction != null)) of the handleResponse function

Network Streams have a habit of advertising data available even when they are not active. Furthermore, there is no way for the receiver to know how long the incoming stream is unless the sender advertises it before hand.

        /// <summary>
        /// Method designed to allow the sending of Byte[] data to the Peer
        /// Because this is using NetworkStreams - the first 4 bytes sent is the data length
        /// </summary>
        /// <param name="TheMessage"></param>
        public void SendBytesToPeer(byte[] TheMessage)
        {

            try
            {
                long len = TheMessage.Length;

                byte[] Bytelen = BitConverter.GetBytes(len);

                PeerStream.Write(Bytelen, 0, Bytelen.Length);
                PeerStream.Flush();
                PeerStream.Write(TheMessage, 0, TheMessage.Length);
                PeerStream.Flush();
            }
            catch (Exception e)
            {
                //System.Windows.Forms.MessageBox.Show(e.ToString());
            }
        }

Note - the flushing on the sender side might not be needed, but I add it in as it does no harm - Microsoft says that flush does nothing to network streams.

So this code will determine the size of the message you are sending, and then send that to the receiver ahead of your 'actual' message.

        /// <summary>
        /// Incoming bytes are retrieved in this method
        /// </summary>
        /// <param name="disconnected"></param>
        /// <returns></returns>
        private byte[] ReceivedBytes(ref bool disconnected)
        {
            try
            {
                //byte[] myReadBuffer = new byte[1024];
                int receivedDataLength = 0;
                byte[] data = { };
                int len = 0;
                int i = 0;
                PeerStream.ReadTimeout = 15000;


                if (PeerStream.CanRead)
                {
                    //networkStream.Read(byteLen, 0, 8)
                    byte[] byteLen = new byte[8];
                    if (_client.Client.IsConnected() == false)
                    {
                        //Fire Disconnect event
                        if (OnDisconnect != null)
                        {
                            disconnected = true;
                            OnDisconnect(this);
                            return null;
                        }
                    }
                    while (len == 0)
                    {
                        PeerStream.Read(byteLen, 0, 8);

                        len = BitConverter.ToInt32(byteLen, 0);
                    }
                    data = new byte[len];

                    PeerStream.Read(data, receivedDataLength, len);

                    return data;
                }



            }
            catch (Exception E)
            {

                //System.Windows.Forms.MessageBox.Show("Exception:" + E.ToString());
            }
            return null;
        }

This code will wait until the receiver has detected an incoming stream length, then it will attempt to read that exact length. Don't worry about the OnDisconnect bit- that's just some code I left in from a project I was doing. You may want to consider adding a Thread.Sleep within the while(len == 0) loop, to save your CPU Cycles.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM