2

I'm very new to the TCP/IP stack from Microchip and I have succesfully created my own basic TCP server with the help of some of the examples in the Harmony folder. I would like to expand my TCP server to cater to multiple client connections on the same port but I'm not entirely sure the best way to go about this.

Below is a snippit of my basic Server application.

void TCP_SERVER_Tasks ( void )
{
//Handle for the network interface
static TCPIP_NET_HANDLE networkInterfaceHandle;

//IP Address assigned to DHCP Client
static IPV4_ADDR hostIPAddress;

//Handle for TCP Client
static TCP_SOCKET TCPSocketHandle = INVALID_SOCKET;

//System Timer Tick Values
static uint32_t statusRequestTick;
static uint32_t timeoutTick;

//Temporary Buffer for Storage of received UDP/TCP Data
uint8_t receivedDataBuffer[128];
uint16_t numberDataBytesToProcess;

//Check if the network interface has become disconnected.
//Close any open sockets, and goto NETWORKCOMS_STATE_INIT state
if (tcp_serverData.state > NETWORKCOMS_STATE_WAIT_FOR_LINK &&
    TCPIP_STACK_NetIsLinked(networkInterfaceHandle) == false)
{
    if (TCPSocketHandle != INVALID_SOCKET)
    {
        //Close the Open TCP Socket
        TCPIP_TCP_Close(TCPSocketHandle);
        TCPSocketHandle = INVALID_SOCKET;
    }

    tcp_serverData.state = NETWORKCOMS_STATE_WAIT_FOR_LINK;
}

/* Check the application's current state. */
switch ( tcp_serverData.state )
{
    /* Application's initial state. */
    case TCP_SERVER_STATE_INIT:
    {
        //Wait for the TCPIP Stack and System Timer Service to become initialized
        if (TCPIP_STACK_Status(sysObj.tcpip) == SYS_STATUS_READY &&
            SYS_TMR_Status(sysObj.sysTmr) == SYS_STATUS_READY)
        {
            if (TCPIP_STACK_NumberOfNetworksGet() > 0)
            {
                //Get a handle to the network interface
                //For this application only one interface is used
                networkInterfaceHandle = TCPIP_STACK_IndexToNet(0);
            }

            timeoutTick = SYS_TMR_TickCountGet();
            tcp_serverData.state = NETWORKCOMS_STATE_WAIT_FOR_LINK;
        }

        break;
    }

    case NETWORKCOMS_STATE_WAIT_FOR_LINK:
    {
        //Determine if the network interface is connected
        if (TCPIP_STACK_NetIsLinked(networkInterfaceHandle))
        {
            //Check if a DHCP Server can be found on the network
            if (TCPIP_DHCP_IsBound(networkInterfaceHandle))
            {
                hostIPAddress.Val = TCPIP_STACK_NetAddress(networkInterfaceHandle);
                tcp_serverData.state = NETWORKCOMS_SETUP_TCP_SERVER;

            }

        }

        break;
    }

    case NETWORKCOMS_SETUP_TCP_SERVER:
    {
        //Setup the TCP Server on the port defined by the TCP_SERVER_PORT constant.
        //Store the returned socket handle in the TCPSocketHandle variable.

        TCPSocketHandle = TCPIP_TCP_ServerOpen(IP_ADDRESS_TYPE_IPV4, TCP_SERVER_PORT, 0);

        // Verify that the socket opened correctly
        if (TCPSocketHandle != INVALID_SOCKET )
        {
            tcp_serverData.state = NETWORK_WAIT_FOR_CONNECTION;
        }
        break;
    }

    case NETWORK_WAIT_FOR_CONNECTION:
    {
        // Periodically check to see if a Client has connected
        if( TCPIP_TCP_IsConnected(TCPSocketHandle) )
        {
            tcp_serverData.state = NETWORK_SERVICE_CONNECTION;
        }
        break;
    }

    case NETWORK_SERVICE_CONNECTION:
    {
        // Make sure that the connection is still available
        if ( !TCPIP_TCP_IsConnected(TCPSocketHandle) )
        {
            tcp_serverData.state = NETWORK_WAIT_FOR_CONNECTION;

        }

        else
        {
            if ( TCPIP_TCP_PutIsReady(TCPSocketHandle) > 10 )
            {
                TCPIP_TCP_StringPut(TCPSocketHandle, "HELLO!!\r\n\0");
            }

            tcp_serverData.state = NETWORK_CLOSE_CONNECTION;
        }
        break;
    }

    case NETWORK_CLOSE_CONNECTION:
    {
        TCPIP_TCP_Close(TCPSocketHandle);

        tcp_serverData.state = NETWORKCOMS_SETUP_TCP_SERVER;
        break;
    }


    /* The default state should never be executed. */
    default:
    {
        /* TODO: Handle error in application's state machine. */
        break;
    }
  }
}
 `

Right now if a connection comes in on the port the code responds with HELLO! and then closes the connection.

Before I begin changing the code to service multiple client I need some clarifiaction. Do I need to bind the server socket to my local address before I can begin accepting multiple clients and why?

Can I use the Berkley_Server example located in the Harmony folder as a general template on how to build a general TCP server with multiple client access?

Any clarification or insight will be very appreciated.

R. Johnson
  • 102
  • 12
  • Usually you create a separate socket for each incoming connection on the listening port using Accept() – Marco van de Voort Sep 27 '16 at 15:35
  • You are correct, it seems that Harmony, at a lower level, takes care of that process for you. You only need to poll the 'Socket Handle' that Harmony generates for you in order listen to ports. The examples only show how to do this with 1 socket though aside from the Berkley example. Would it be helpful if I posted the berkley example as well? – R. Johnson Sep 27 '16 at 15:39
  • That's the "listen", but for multiple connections you need accept too. Also non BSD you'd need to have some datastructure per connection anyway, since you must track the state of each individual connection for the various TCP/IP connection states. I have MLA sourcecode here, and cut down the stack for own purposes in the past, but that was purely UDP, which is simpler. – Marco van de Voort Sep 27 '16 at 15:47
  • I just looked at the demoes, and generic_tcp_server is a dud. It doesn't really track multiple connections, just echos each packet back to where it came from without state. – Marco van de Voort Sep 27 '16 at 15:49
  • Ya, I noticed that too :( if you look at the berkley server example it shows that the stack can accept and manage multiple clients but it does not really help me as I am not building a berkley server. – R. Johnson Sep 27 '16 at 15:51
  • It seems a bit unorthodox but if one absolutly wanted to use the TCPIP functions built in the stack couldn't I create an array of server sockets that all listen on the same port and simply switch between them to check for an incoming byte stream? I'm trying to think of what Microchip was thinking when they designed this. – R. Johnson Sep 27 '16 at 16:06
  • You still have to reconstruct (and handle resends etc) on a per stream basis. I do this on my own derivative, a wiznet UDP server which only requires packets (not multi packet streams). I think that one was based on the "announce" demo a long,long time ago. And I don't think it is microchip, it is simply the way TCP works. – Marco van de Voort Sep 27 '16 at 20:12

0 Answers0