IP and Ping

@ Wayne - When the Client_Connect callback is invoked, the call to _client.EndConnect will do one of two things

  1. Returns immediately without raising an exception which means that something on the network was listening on the IP address and port combination and accepted the connection.

  2. It will raise a SocketException indicating that the connection could not be established.

Since I do not have the Panda or the Ethernet shield you are using, I cannot actually test your scenario and therefore cannot accurately guess what might be happening. However the following come to mind

  • You have another device on the network that is accepting the connection
  • The Panda or the shield is not really off and is accepting the connection

Maybe you can post the exception messages that you are receiving when you get the ‘system error’, that might shed some light on your issues.

B) No, there is no notion in TCP of sending a notification on the network to inform other devices that the new device is available and they can now re-establish communication. This would have to be something at the application layer.

@ taylorza - thanks for the further advice, your last post provided a good clue: it was the port. To be sure, I tried a random IP address (that’s definitely not on the network) and the BeginConnect still ended successfully…as long as it was port 80. Once I changed the port, the BeginConnect executed, but the button remained disabled. I think my PC/router TCP configuration, are such that any request made on port 80 is accepted (perhaps because I also run IIS on the PC and localhost uses port 80). Thanks, again!

@ Wayne - I am glad this helped!

@ Wayne,

don’t forget to mark this question “answered”

@ taylorza and @ Brett:

I’ve been using the code provided by taylorza with good success (really, thanks). But, I noticed a peculiarity: if I close my client application on my laptop that was communicating with the FEZ, and restart it, I can no longer communicate with the FEZ on the same IP address. I have to reboot the FEZ and, then, restart my client application. Is there a way to reconnect to that IP address?

This simulates a broken connection…kind of. Perhaps, the program on the FEZ, after binding to the initial incoming request, will no longer accept any additional requests. Can I make it accept a new incoming client request, get rid of the old client, and make the new incoming client request be the client that it processes?

It seems like your code just doesn’t handle a disconnected session properly. Panda has only 4 sockets, and depending on how you’re using it you may have multiple sockets reserved and not accessible, so you probably are hitting that limit with a new open socket request. I think you probably need to investigate with a debugger attached (VS is awesome for that have you found?) so you know where the code is “stuck” and figure out how to backtrack and handle that gracefully

The debugger on VS is excellent, I admit. My failing is in C# (I’m normally a VB user) and in working with Threads and TcpClients/NetworkStreams. I’m using taylorza’s code (almost) verbatim (see below). It’s hard to tell if the Thread that listens for incoming requests is still listening after it has already accepted the first request and, if it is, how to “kill” the first client, upon receiving a new request, and create a new client (or reuse the existing client)


public partial class Program
  {
    // This method is run when the mainboard is powered up or reset.   
    void ProgramStarted()
    {
      // Setup the network
      ethernet.UseStaticIP("192.168.1.7", "255.255.255.0", "192.168.1.1");
 
      // Start a new thread to listen for incomming connections
      // I believe you can do exactly this in your main function
      new Thread(() =>
      {
        // This code is running is a separate thread.
        Socket socket1 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        EndPoint ep1 = new IPEndPoint(IPAddress.Any, 80);
        socket1.Bind(ep1);
        socket1.Listen(5);
        while (true)
        {
          // Wait for a client to connect
          Socket client = socket1.Accept();
 
          // Client has connected, we hand it off
          // to another thread to handle the client
          // communication.
          ClientConnection.Process(client);
        }
      }).Start();
 
      Debug.Print("Program Started");
    }    
  } 

class ClientConnection
  {
    private const int BufferSize = 1024;
 
    private Socket _client;
    private byte[] _bytes = new byte[BufferSize];
    private ByteBuffer _buffer = new ByteBuffer();
 
    public static void Process(Socket client)
    {
      ClientConnection connection = new ClientConnection(client);
      connection.Start();
    }
 
    private ClientConnection(Socket client)
    {
      _client = client;
    }
 
    private void Start()
    {
      new Thread(ProcessData).Start();
    }
 
    private void ProcessData()
    {
      State state = State.ReadLength;
      byte messageLength = 0;
 
      while (true)
      {
        int bytesReceived = _client.Receive(_bytes);
        for (int i = 0; i < bytesReceived; i++)
        {
          _buffer.Enqueue(_bytes[i]);
        }
 
        while (_buffer.Count > 0)
        {
          switch (state)
          {
            case State.ReadLength:
              if (_buffer.Count >= 1)
              {
                messageLength = _buffer.Dequeue();
                state = State.ReadMessage;
              }
              break;
 
            case State.ReadMessage:
              if (_buffer.Count >= messageLength)
              {
                byte[] messageBytes = new byte[messageLength];
                _buffer.Dequeue(messageBytes);
                Debug.Print(new string(Encoding.UTF8.GetChars(messageBytes)));
                state = State.ReadLength;
              }
              break;
          }
        }
      }
    }
 
    enum State
    {
      ReadLength,
      ReadMessage
    }
  }
  • I left out routines Enqueue and Dequeue.

I would look at this:

        while (true)
        {
          // Wait for a client to connect
          Socket client = socket1.Accept();
 
          // Client has connected, we hand it off
          // to another thread to handle the client
          // communication.
          ClientConnection.Process(client);
        }

I actually think you need to close the client object and dispose it. Put a breakpoint at the accept and process calls to see when you hit that in your code.

@ Wayne, unfortunately I cannot test this right now, but to handle the disconnects you need two things.

  1. If the client performs a clean shutdown and close of the connection the _client.Receive will return 0
  2. If the client “disappears” then _client.Receive will throw a SocketException

In ProcessData you would need something like the following…


  try
  {
    while (true)
    {
       int bytesReceived = _client.Receive(_bytes);
           
       if (bytesReceived == 0) break;
       ...
       ...
    }
       
    // Client initiated a graceful shutdown so we can close 
    // the connection on the server side
    _client.Close();
}
catch (SocketException)
{
   // Something when wrong with the client so lets release the resources on our side
  _client.Close();
}

I will double check the above when I get back from work this evening, but hopefully this will help.

NOTE: Int he case of a non-graceful shutdown you might have issues that @ Brett has mentioned with the number of available sockets. If the shutdown was not graceful (ie the client did not shutdown the send half of the Socket) then the connected socket will go into a ‘time wait’ state. You will need to wait for this to expire.

@ Wayne - Here is the original ProcessData with the addtional error checking. I quickly tested this and it handle the unexpected connection termination as well as the graceful shutdown. Note however, that the unexpected disconnection might be an issue with the the time wait states as I mentioned. I do not have a Panda II so I cannot test the limit.


private void ProcessData()
    {
      State state = State.ReadLength;
      byte messageLength = 0;

      try
      {
        while (true)
        {
          int bytesReceived = _client.Receive(_bytes);

          // If received 0 bytes the client gracefully shutdown and closed the socket
          if (bytesReceived == 0) break;

          for (int i = 0; i < bytesReceived; i++)
          {
            _buffer.Enqueue(_bytes[i]);
          }

          while (_buffer.Count > 0)
          {
            switch (state)
            {
              case State.ReadLength:
                if (_buffer.Count >= 1)
                {
                  messageLength = _buffer.Dequeue();
                  state = State.ReadMessage;
                }
                break;

              case State.ReadMessage:
                if (_buffer.Count >= messageLength)
                {
                  byte[] messageBytes = new byte[messageLength];
                  _buffer.Dequeue(messageBytes);
                  Debug.Print(new string(Encoding.UTF8.GetChars(messageBytes)));
                  state = State.ReadLength;
                }
                break;
            }
          }
        }
      }
      catch (SocketException)
      {
        // Something went wrong reading the socket
        // the client possibly lost connection or 
        // under when a non-graceful shutdown.

        // Note: You might want to check for specific socket error codes here,
        // but at this point there is something wrong so you might as well
        // just log the error and terminate the connection (this will happen in the finally block)
      }
      finally
      {
        // If we reach here the client is no longer connected so we
        // can release our server-side resources
        if (_client != null) _client.Close();
      }
    }

Thanks for this update on the code (and sorry for the late reply). It works beautifully and allows for multiple connects/disconnects very smoothly. I made a slight mod to the program to send an acknowledgement back to the client when a message is received. Like this:

case State.ReadMessage:
                if (_buffer.Count >= messageLength)
                {
                  byte[] messageBytes = new byte[messageLength];
                  _buffer.Dequeue(messageBytes);
                  Debug.Print(new string(Encoding.UTF8.GetChars(messageBytes)));
                  //-------------------------------------------------------
                  // send acknowledgement
                  string serverResponse = "Server Ack|";
                  Byte[] sendBytes = Encoding.UTF8.GetBytes(serverResponse);
                  _client.Send(sendBytes);
                 //-------------------------------------------------------
                  state = State.ReadLength;
                }

And, this has been working fine in testing. I did, however, create a scenario that failed and created an exception that the program didn’t catch: I had my client application send a message to this program and close the client application immediately before this program had a chance to send back the acknowledgement. As expected, it created an exception that the client was closed. In debug mode, I got a popup about the exception and the output window showed the exception, but, however, the exception didn’t get handled by the Catch region of the code.

UPDATE (again):

I moved the acknowledgement to a separate subroutine. As you’ll see below, the code below will close the connection after reporting the exception, but just not sure how to suppress the exception altogether. The good news is that the application continues to run and correcty awaits the next incoming client request. Here’s the code and the exception:


        private void SendMsg(string msg)
        {
            try
            {
                Byte[] sendBytes = Encoding.UTF8.GetBytes(msg);
                _client.Send(sendBytes);
            }
            catch (Exception exc)
            {
                Debug.Print("SendMsg: exception caught - " + exc);
            }
            finally
            {
                //
            }
        }

Output window:

client accepted
CONNECT
#### Exception System.Exception - 0x00000000 (5) ####
#### Message: Socket is closed
#### GHIElectronics.NETMF.Net.SocketNative::send [IP: 0062] ####
#### GHIElectronics.NETMF.Net.Sockets.Socket::Send [IP: 0029] ####
#### GHIElectronics.NETMF.Net.Sockets.Socket::Send [IP: 0010] ####
#### FEZPandaConnect.ClientConnection::SendMsg [IP: 000f] ####
#### FEZPandaConnect.ClientConnection::ProcessData [IP: 00f1] ####
A first chance exception of type ‘System.Exception’ occurred in GHIElectronics.NETMF.W5100.dll
SendMsg: exception caught - System.Exception: Socket is closed
ProcessData: client closed
The thread ‘’ (0x5) has exited with code 0 (0x0).

@ Wayne - Why are you concerned with suppressing the exception? This is an exceptional condition, at some point between receiving the client data and sending the ‘ack’ something exceptional occurred, so the system correctly reports the exception and you handle it in a way that is appropriate to your application.

The fact that you see the exception in the Debug window is just because you are running under the debugger and the debugger is being notified of the exception, this is called a ‘First chance exception’, because you handle the exception it does not go beyond the first chance exception reported to the debugger.

Ok, thanks. It’s working pretty well, and I wanna share what I’ve got, so here are some of the unique parts. The only things to note are that I left out some of the long routines, and I made the _client variable global, and LastCommand is just tracking the last received message to compare to the new received message, timerInterval shuts down the motors if no message is received (the client application, upon connection, sends a regular heartbeat which resets the timer on each beat).

    public static class Globals
    {
        static TimerCallback timerDelegate = new TimerCallback(CheckMotors.StopMotors);
        public static Timer shutdownTimer = new Timer(timerDelegate, null, -1, -1);
        public static int timerInterval = 5000;
        public static double leftMotorSpeed, rightMotorSpeed;
        public static double VELOCITY_RATE = 0.7;
        public static double VELOCITY_EXPONENT = 0.7;
        public static double VELOCITY_DIVISOR = 1;
        public static double VELOCITY_STOP = 0;
        public static string LastCommand = "";
        public static Socket _client;
    }
    
    public class Program2
    {
        public static void Main()
        {
            Debug.EnableGCMessages(false);
            //Debug.GC(true);

            Thread.Sleep(3000);                             // wait for motor driver to settle
            ClientConnection.InitializeMotordriver();       // initialize motor driver
            FEZTouchDriver.LcdInit();                       // initialize lcd screen
            
            // Setup the network
            //ethernet.UseStaticIP("192.168.0.101", "255.255.255.0", "192.168.0.1");
            //Microsoft.SPOT.Net.NetworkInformation.NetworkInterface NI = Microsoft.SPOT.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()[0];
            //NI.EnableStaticIP("192.168.1.4", "255.255.255.0", "192.168.1.1");
            //
            //byte[] mac = { 0x00, 0x26, 0x1C, 0x7B, 0x29, 0xE8 };
            //WIZnet_W5100.Enable(SPI.SPI_module.SPI1, (Cpu.Pin)FEZ_Pin.Digital.Di10, (Cpu.Pin)FEZ_Pin.Digital.Di7, true);
            //Dhcp.EnableDhcp(mac, "panda");

            byte[] ip = { 192, 168, 1, 7 };
            byte[] subnet = { 255, 255, 255, 0 };
            byte[] gateway = { 192, 168, 1, 1 };
            byte[] mac = { 0x00, 0x26, 0x1C, 0x7B, 0x29,0xE8 };
            byte[] dns = { 192, 168, 1, 1 };
 
            WIZnet_W5100.Enable(SPI.SPI_module.SPI1, (Cpu.Pin)FEZ_Pin.Digital.Di10,(Cpu.Pin)FEZ_Pin.Digital.Di7, true); 
            NetworkInterface.EnableStaticIP(ip, subnet, gateway, mac);
            NetworkInterface.EnableStaticDns(dns);
            
            Debug.Print("Network settings:");
            Debug.Print("IP Address: " + new IPAddress(NetworkInterface.IPAddress).ToString());
            Debug.Print("Subnet Mask: " + new IPAddress(NetworkInterface.SubnetMask).ToString());
            Debug.Print("Default Getway: " + new IPAddress(NetworkInterface.GatewayAddress).ToString());
            Debug.Print("DNS Server: " + new IPAddress(NetworkInterface.DnsServer).ToString());
            FEZTouchDriver.WriteLine(" ");
            FEZTouchDriver.WriteLine("Network settings:");
            FEZTouchDriver.WriteLine("IP Address: " + new IPAddress(NetworkInterface.IPAddress).ToString());
            FEZTouchDriver.WriteLine("Subnet Mask: " + new IPAddress(NetworkInterface.SubnetMask).ToString());
            FEZTouchDriver.WriteLine("Default Getway: " + new IPAddress(NetworkInterface.GatewayAddress).ToString());
            FEZTouchDriver.WriteLine("DNS Server: " + new IPAddress(NetworkInterface.DnsServer).ToString());

            // Start a new thread to listen for incomming connections
            // I believe you can do exactly this in your main function
            new Thread(() =>
            {
                // This code is running is a separate thread.
                Socket socket1 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                EndPoint ep1 = new IPEndPoint(IPAddress.Any, 80);
                socket1.Bind(ep1);
                socket1.Listen(1);
                Debug.Print("Main: Listening");
                
                while (true)
                {
                    // Wait for a client to connect
                    Socket client = socket1.Accept();
                    Debug.Print("Main: Client accepted");
                    // Client has connected, we hand it off to another thread to handle the client communication.
                    ClientConnection.Process(client);
                }
            }).Start();

            Debug.Print("Main: Program Started");
            FEZTouchDriver.WriteLine(" ");
            FEZTouchDriver.WriteLine("Program Started");
        }
    }
    class ClientConnection
    {
        private const int BufferSize = 1024;

        //private Socket _client;
        private byte[] _bytes = new byte[BufferSize];
        private ByteBuffer _buffer = new ByteBuffer();

        public static void Test()
        {
            //
        }

        public static void Process(Socket client)
        {
            ClientConnection connection = new ClientConnection(client);
            connection.Start();
        }

        private ClientConnection(Socket client)
        {
            //_client = client;
            Globals._client = client;
        }

        private void Start()
        {
            new Thread(ProcessData).Start();
        }

        private void SendMsg(string msg)
        {
            try
            {
                Byte[] sendBytes = Encoding.UTF8.GetBytes(msg);
                //_client.Send(sendBytes);
                Globals._client.Send(sendBytes);
            }
            catch (Exception exc)
            {
                Debug.Print("SendMsg: exception caught - " + exc);
            }
            finally
            {
                //
            }
        }

        private void ProcessData()
        {
            State state = State.ReadLength;
            byte messageLength = 0;

            try{

            while (true)
            {
                //int bytesReceived = _client.Receive(_bytes);
                int bytesReceived = Globals._client.Receive(_bytes);

                // If received 0 bytes the client gracefully shutdown and closed the socket
                if (bytesReceived == 0) break;

                for (int i = 0; i < bytesReceived; i++)
                {
                    _buffer.Enqueue(_bytes[i]);
                }

                while (_buffer.Count > 0)
                {
                    switch (state)
                    {
                        case State.ReadLength:
                            if (_buffer.Count >= 1)
                            {
                                messageLength = _buffer.Dequeue();
                                state = State.ReadMessage;
                            }
                            break;

                        case State.ReadMessage:
                            if (_buffer.Count >= messageLength)
                            {
                                byte[] messageBytes = new byte[messageLength];
                                _buffer.Dequeue(messageBytes);

                                //interpret received message
                                string receivedMsg = new string(Encoding.UTF8.GetChars(messageBytes));
                                receivedMsg = receivedMsg.ToUpper();
                                Debug.Print("ProcessData(" + DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss") + "): " + receivedMsg);

                                //send acknowledgement
                                SendMsg("Server Ack: " + receivedMsg + "|");

                                //evaluate message
                                EvaluateMessage(receivedMsg);

                                state = State.ReadLength;
                            }
                            break;
                    }
                }
            }

            }
            catch (SocketException)
            {
                // Something went wrong reading the socket
                // the client possibly lost connection or 
                // under when a non-graceful shutdown.

                // Note: You might want to check for specific socket error codes here,
                // but at this point there is something wrong so you might as well
                // just log the error and terminate the connection (this will happen in the finally block)
                Debug.Print("ProcessData: exception caught");
            }
            finally
            {
                // If we reach here the client is no longer connected so we
                // can release our server-side resources
                if (Globals._client != null) Globals._client.Close();
                Debug.Print("ProcessData: client closed");
            }

        }


    public class FEZTouchDriver
    {
        public static FEZ_Components.FEZTouchConsole lcdConsole;

        public static void Write(string message)
        {
            lcdConsole.Write(message);
        }

        public static void WriteLine(string message)
        {
            lcdConsole.WriteLine(message);
        }

        public static void Init()
        {
            LcdInit();
        }

        public static void LcdInit()
        {
            FEZ_Components.FEZTouchConsole.LCDConfiguration lcd_config =
                new FEZ_Components.FEZTouchConsole.LCDConfiguration(
                FEZ_Pin.Digital.Di28, FEZ_Pin.Digital.Di20,
                FEZ_Pin.Digital.Di22, FEZ_Pin.Digital.Di23,
                new FEZ_Pin.Digital[8]
                {
                    FEZ_Pin.Digital.Di51, FEZ_Pin.Digital.Di50,
                    FEZ_Pin.Digital.Di49, FEZ_Pin.Digital.Di48,
                    FEZ_Pin.Digital.Di47, FEZ_Pin.Digital.Di46,
                    FEZ_Pin.Digital.Di45, FEZ_Pin.Digital.Di44
                }, FEZ_Pin.Digital.Di24, FEZ_Pin.Digital.Di26);

            lcdConsole = new FEZ_Components.FEZTouchConsole(lcd_config,
                ConsoleColor.White, ConsoleColor.Blue);

            lcdConsole.Clear();
        }
    }

        static public void InitializeMotordriver()
        // Pre:     Character "170" (= Binary 1010 1010) needs to be send over serial port to Sabertooth 2x5 motor driver so it can determine the baud rate.
        // Post:    Character "170" is send over the serial port to the Sabertooth 2x5 motor driver and Sabertooth has determined the baud rate 
        //          Sabertooth 2x5A motor driver sets to right PWM therefore right motor speed.
        {
            byte motordriverInitialisationValue = 170;

            SerialPort SerialCOM1 = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);     // Set Serial port COM to 9600 Baud, No parity bit, 8 data bits and 1 stop bit. (8N1 protocol) (Pin2; on FEZ Domino board)
            SerialCOM1.Open();                                                                      //Open the Serial Port for communication (.NetMF 4.1 requirement)
            //SerialCOM1.WriteTimeout = 1000;                                                       //The WriteTimeout; makes shure it doesn't write forever (optional)
            SerialCOM1.Write(new byte[] { motordriverInitialisationValue }, 0, 1);                  // transmit data array (of 1 items) to serial port.
            Debug.Print("InitializeMotordriver: Value - " + motordriverInitialisationValue);       //# Text for Visual studio 2010 .net debug output monitor
            SerialCOM1.Close();                                                                     // Close serial port, after sending data.
        }

private void EvaluateMessage(string receivedMsg).....

static public void DriveMotor(byte address, byte direction, byte motorspeed)............


@ Wayne, Thanks for sharing…

I have a question, why did you need to move the ‘_client’ out of the ClientConnection class into Globals? The risk with this is that if additional connections are made to the device the _client instance will be clobbered.

Don’t get me wrong, it is reasonable to have a solution that can only accept a single connection, if that is the nature of your application. The concern is that the current solution will accept additional connections, so if you do in fact want to support multiple concurrent connections then you should move _client back to the ClientConnection class, if there was a technical issue that forced this I am certain we can find an alternate solution for you.

Alternatively, if you want to ensure that you do not accept more than one connection at a time, then it would be a relatively minor change to enforce this constraint and not risk additional connections coming in and overwriting your global _client instance.

@ taylorza: I’m gonna move it back to the ClientConnection routine. I was pursuing another idea (like shutting down the client from another class) and didn’t change it back because it was surviving my tests - thanks!

Hey, I have a different question - I power my FEZPanda2 from a 5V output coming from my motor driver and noticed that when I drive the motors at a higher speed, the serial port or the tcp/ip channel on the FEZ stops communicating or the program stops running (I think it’s this one). I noticed that some other people in the forum had similar issues, so I measured the voltage and I have a steady 4.98 volts going into the 5V IN/OUT socket, and the one of the GND sockets going to 0V. And, weirdly enough, if I plug in the USB cable to my PC, the program starts running correctly again…and I think that USB provides about 4.5-5.0V, too. Have you come across this issue before? I have a 12v source in my robot - would it be better to power this board by providing 12v to the Vin socket (under the GND sockets), instead?

Please start new post and mark as question please :slight_smile:

LOL - okay, good point. :slight_smile: