Main Site Documentation

System.Net.Sockets.Socket.Receive function sometimes appends a zero to the end of data received


#1

I have a TCP server in a Raptor board, with MF 4.2, that has a problem: sometimes the Socket object appends a zero byte onto the end of a data message. About half the time I receive the correct size packet,and half the time I receive a packet with a zero appended at the end.
I am the using System.Net.Sockets.Socket class. I used WireShark to display the IP datagrams sent to the board, and the extra zero never appears in WireShark, even when it is received by the Socket.Receive function. Any help? Here is my entire socket server source code. After a incoming connection is established, m_clientSkt.Poll() function detects when data is available to be received, and m_clientSkt.Receive() gets the received byte array.


using System;
using Microsoft.SPOT;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using GHINET = GHI.Premium.Net;
using DeviceHive;
using Configuration;
using KioskUtility;

namespace SocketServer
{

    public class TCPServerConstants
    {
        public const int BackLogCount = 4;  //4;     //max number of connections on the listening port
    }

    /// <summary>     
    /// TCP/IP Server
    /// </summary>     
    public class TCPServer
    {
        private const int SERVER_PORT = 1000;
        private Socket m_serverSkt;
        private int m_port;
        private Thread m_serverThread;
        private GHINET.EthernetENC28J60 m_eth;
        private AutoResetEvent m_CableConnectedEvent;
        public bool m_srvRunning { get; set; }
        // On Message Received event         
        public event ClientMsgRxDelegate OnMessageRx;
        public Clienthandler[] m_handlerArray { get; set; }
        private int m_MaxMessageSize;
        private DeviceEngine m_ThisDevice;

        public TCPServer(DeviceEngine dev)
            : this(dev, SERVER_PORT, 0)
        { }
        public TCPServer(DeviceEngine dev, int port)
            : this(dev, port, 0)
        { }
        public TCPServer(DeviceEngine dev, int port, int MaxMessageSize)
        {
            m_ThisDevice = dev;
            m_port = port;
            m_srvRunning = false;
            m_serverSkt = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream, ProtocolType.Tcp);
            m_handlerArray = new Clienthandler[TCPServerConstants.BackLogCount];
            m_CableConnectedEvent = new AutoResetEvent(false);
            m_MaxMessageSize = MaxMessageSize;
        }

        /// <summary>
        /// Start the Server - listen for connections on a new thread
        /// </summary>
        /// <returns></returns>
        public IPEndPoint Start( GHINET.EthernetENC28J60 _eth)
        {
            IPEndPoint svrEndPoint=null;
            if (m_srvRunning)
            {
                // only allow one server thread at a time
                Debug.Print("TCP Server not started - only one TCPServer instance allowed");
                return null;
            }
            m_eth = _eth;
            m_eth.CableConnectivityChanged += new GHINET.EthernetENC28J60.CableConnectivityChangedEventHandler(eth_CableConnectivityChanged);
            m_srvRunning = true;
            //Create local endpoint and bind to socket
            svrEndPoint = new IPEndPoint(IPAddress.Any, m_port);
            m_serverSkt.Bind(svrEndPoint);
            m_serverSkt.Listen( TCPServerConstants.BackLogCount );  // limit number of connections 
            Debug.Print("Server Listening..");
            //create and start our main server thread
            m_serverThread = new Thread(ProcessServer);
            m_serverThread.Start();
            return svrEndPoint;
        }

        /// <summary>
        /// /// Fire our message received event
        /// </summary>
        /// <param name="args"></param>
        private void MessageRx(ClientEventArgs args)
        {
            if (OnMessageRx != null)
            {
                OnMessageRx(this, args);
            }
        }

        /// <summary>
        /// Count the number of TCP clients connected to this server
        /// </summary>
        /// <returns></returns>
        private int GetCountConnectedClients()
        {
            int Count = 0;
            Clienthandler handler;
            for (int index = 0; index < TCPServerConstants.BackLogCount; index++)
            {
                handler = m_handlerArray[index];
                if ( (handler != null) && (handler.m_clientConnected) )
                {
                    Count++;
                }
            }
            return Count;
        }

        /// <summary>
        /// Find the first available Clienthandler slot in the m_handlerArray
        /// </summary>
        /// <param name="slot">Returns the index in the m_handlerArray that can be used for a new Clienthandler object</param>
        /// <returns>true if an available slot was found</returns>
        private bool GetFirstUnusedClientSlot(out int slot)
        {
            bool found=false;
            slot = 0;
            Clienthandler handler;
            for ( int index=0; ((index < TCPServerConstants.BackLogCount) && (!found)); index++)
            {
                handler = m_handlerArray[index];
                if (handler == null)
                {
                    found = true;
                    slot = index;
                }
                else if (!handler.m_clientConnected)
                {
                    found = true;
                    slot = index;
                }
            }
            return found;
        }

        /// <summary>
        /// This is our main server listening thread         
        /// </summary>         
        private void ProcessServer()
        {
            int slot;
            while (m_srvRunning)
            {
                try
                {
                    if (!m_eth.IsCableConnected)
                    {
                        Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " SocketServer.ProcessServer( tcp port = " + m_port.ToString() + " ): Ethernet cable is not connected, waiting for connection");
                        m_CableConnectedEvent.WaitOne();
                        Thread.Sleep(3000);
                    }

                    // wait for a connection - will block                 
                    Socket client = m_serverSkt.Accept();
                    Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " SocketServer.ProcessServer( tcp port = " + m_port.ToString() + " ): Connection to client");

                    // create a new session for the connection                 
                    if (GetFirstUnusedClientSlot(out slot))
                    {
                        Clienthandler handler = new Clienthandler(this, client);
                        m_handlerArray[slot] = handler;
                        Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") + " Number of Clients: " + GetCountConnectedClients().ToString() + " Connected to TCP Port " + m_port.ToString());
                    }
                    else
                    {
                        Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff") +  " SocketServer.ProcessServer( tcp port = " + m_port.ToString() + " ): Closing client socket, no more connections allowed");
                        client.Close();
                    }
                }
                catch (SocketException ex)
                {
                    KioskUtilities.LogException( "SocketServer.ProcessServer( tcp port = " + m_port.ToString() + " ): exception: ",  ex);
                }
                catch (Exception ex)
                {
                    KioskUtilities.LogException("SocketServer.ProcessServer( tcp port = " + m_port.ToString() + " ): exception: ",  ex);
                    m_srvRunning = false;
                    KioskUtilities.Reboot();
                }
            }
            Debug.Print("SocketServer.ProcessServer( tcp port = " + m_port.ToString() + " ): exited server loop");
        }

        void eth_CableConnectivityChanged(object sender, GHINET.EthernetENC28J60.CableConnectivityEventArgs e)
        {
            try
            {
                if (e.IsConnected)
                {
                    Debug.Print("TCPServer.CableConnectivityChanged Event - Ethernet cable is connected");
                    m_CableConnectedEvent.Set();
                }
                else
                {
                    Debug.Print("TCPServer.CableConnectivityChanged Event - Ethernet cable is not connected");
                }
            }
            catch (Exception ex)
            {
                KioskUtilities.LogException("TCPServer.eth_CableConnectivityChanged() exception ",  ex);
                KioskUtilities.Reboot();
            }
        }


        #region client handler class
        /// <summary>         
        /// Client socket handler helper class         
        /// </summary>         
        public class Clienthandler
        {
            public Socket m_clientSkt { get; set;}
            public TCPServer m_serverSkt { get; set; }
            private Thread m_clientThread;
            private const int MICROSECS_SEC = 1000000;
            private int m_readTimeout = 0;
            public bool m_clientConnected { get; set; }
            private int m_MaxMessageSize;
            private byte[] m_MessageBuffer=null;

            public Clienthandler(TCPServer server, Socket client)
            {
                m_serverSkt = server;
                m_clientSkt = client;
                m_readTimeout = 30 * MICROSECS_SEC;
                m_clientConnected = true;
                m_MaxMessageSize = server.m_MaxMessageSize;
                if (m_MaxMessageSize > 0)
                    m_MessageBuffer = new byte[m_MaxMessageSize];
                else
                    m_MessageBuffer = null;
                ServiceClient();
            }

            public void ServiceClient()
            {
                // create and start our session thread                 
                m_clientThread = new Thread(ProcessClient);
                m_clientThread.Start();
            }

            /// <summary>             
            /// The session thread             
            /// Listen for messages             
            /// </summary>             
            private void ProcessClient()
            {
                try
                {
                    using (m_clientSkt)
                    {
                        try
                        {

                            Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff")
                                + " Client connected from " + IPAddress.Parse(((IPEndPoint)m_clientSkt.RemoteEndPoint).Address.ToString())
                                + " from port number " + ((IPEndPoint)m_clientSkt.RemoteEndPoint).Port.ToString()
                                + " to port number " + m_serverSkt.m_port.ToString());
                        }
                        catch (Exception ex1)
                        {
                            Debug.Print(ex1.ToString());
                        }
                        while (true)
                        {
                            try
                            {
                                if (m_clientSkt.Poll(m_readTimeout, SelectMode.SelectRead))
                                {
                                    // if read buffer is 0, then no data after timeout means socket may be gone                
                                    int bytesavail = m_clientSkt.Available;
                                    if (bytesavail <= 0)
                                    { // exit thread, close socket                                     
                                        Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff")
                                            + " bytesavail = " + bytesavail.ToString()
                                            + " Client lost, close connection on port " + m_serverSkt.m_port.ToString());
                                        m_clientConnected = false;
                                        break;
                                    }
                                    // we have a message              
                                    byte[] buffer;
                                    if ((m_MaxMessageSize > 0) && (m_MessageBuffer != null) && (bytesavail < m_MaxMessageSize))
                                        buffer = m_MessageBuffer;
                                    else
                                        buffer = new byte[bytesavail];
                                    int bytesRead = m_clientSkt.Receive(buffer, bytesavail, SocketFlags.None);
                                    if (bytesRead <= 0)
                                    {
                                        Debug.Print(DateTime.Now.ToString("HH:mm:ss.fff")
                                            + " bytesRead = " + bytesRead.ToString()
                                            + " Client lost, close connection on port " + m_serverSkt.m_port.ToString());
                                        m_clientConnected = false;
                                        break;
                                    }
                                    ClientEventArgs args = new ClientEventArgs(m_clientSkt.LocalEndPoint, buffer, bytesRead);
                                    //ClientEventArgs args = new ClientEventArgs(m_clientSkt.LocalEndPoint, buffer, bytesavail);
                                    // let server notify of message
                                    m_serverSkt.MessageRx(args);
                                    // check if a response is returned in args
                                    if (args.Response != null)
                                    {
                                        // send back the response                                     
                                        m_clientSkt.Send(args.Response);
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                Debug.Print("Client exception on tcp port " + m_serverSkt.m_port.ToString() + " Exception: " + ex.ToString());
                                m_clientConnected = false;
                                break;
                            }
                        }  //while (true)
                    }  //using (m_clientSkt)
                    m_clientConnected = false;
                    Debug.Print("# Clients: " + m_serverSkt.GetCountConnectedClients().ToString() + " Connected to TCP Port " + m_serverSkt.m_port.ToString());
                }
                catch (Exception ex)
                {
                    Debug.Print("Client exception on tcp port " + m_serverSkt.m_port.ToString() + " Exception: " + ex.ToString());
                    m_clientConnected = false;
                }
            }

        } //private class Clienthandler
        #endregion
    
    }  //public class Server     

    /// <summary>     
    /// Event args for client messages received     
    /// </summary>     
    public class ClientEventArgs:EventArgs
    {         
        public IPEndPoint ClientEndPoint { get; private set; }
        public byte[] Message { get; private set; }
        public int Size { get; private set; }
        public byte[] Response { get; set; }
        
        public ClientEventArgs(EndPoint _clientEP, byte[] _message, int _size)         
        { 
            ClientEndPoint = (IPEndPoint)_clientEP; 
            //if (message == null) return;
            //Message = new byte[message.Length]; 
            //message.CopyTo(Message,0);         
            Message = _message;
            Size = _size;
        }     
    } 
    
    public delegate void ClientMsgRxDelegate(object sender,ClientEventArgs e);
 

}  //namespace SocketServer


/*
    using System; 
    using System.Text; 
    using Microsoft.SPOT; 
    namespace TCPServer 
    {     
        public partial class Program
        {         
            private Server m_tcpServer;
            private int count = 1;
            // This method is run when the mainboard is powered up or reset. 
            void ProgramStarted() 
            {         
            
                string ipAddress = ethernetForMountaineerEth.NetworkSettings.IPAddress;
                int port = 1000;  
                m_tcpServer = new Server(port); 
                m_tcpServer.OnMessageRx +=  new ClientMsgRxDelegate(m_tcpServer_OnMessageRx);
                try
                {
             
                    m_tcpServer.Start();
                    Debug.Print("Server running :" + ipAddress + ":" +  port);
                }
                catch (Exception)
                { 
                    Debug.Print("Error starting server, is ethernet connected?"); 
                }
                // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging.
                Debug.Print("Program Started");
            }
            
            void m_tcpServer_OnMessageRx(object sender, ClientEventArgs e)
            { 
                // note this is not called on main thread 
                // convert byte[] to string 
                string message = new string(Encoding.UTF8.GetChars(e.Message));
                Debug.Print("Rx Msg " + count  + ":" + message);
                Debug.Print("Client :" +  e.ClientEndPoint.Address + ":" + e.ClientEndPoint.Port); 
                // generate a response to send back to the client
                e.Response = Encoding.UTF8.GetBytes(" Message " + count++ +" Received");
            }
        }
    }
 
 */ 




#2

@ dspacek - Our apologies for the delay. Can you create a very minimal example from that server? Ideally a few lines that only accepts one connection and does a basic read to check for the zero? How often would you say the zero is added? Every five requests, ten, twenty?