Client-Server(Daemon) Example

Document created by soledad Employee on Oct 19, 2016
Version 1Show Document
  • View in full screen mode

Hello All,

 


I want to share a client-server project. In this example the server can accept more than one client (Daemon server implementation). This example was created and tested using MQX4.2, CodeWarrior 10.6 and FRDM-K64F boards.

 

 

In general, the client-server model is the most common communication model used by the applications such as HTTP, Telnet, FTP, SSH, and others. In a client-server model, the server listens to client requests and waits for new connections. When a client needs to connect to a server, it sends a request. The server acknowledges the request, and if the client is supported by the server, the connection is established.  

A TCP client-server communication can be implemented as in the following figure.

 

 

 

 

SETTING THE RTCS

Below are presented the steps required to set the RTCS with the default settings:

  1. Create the RTCS. This step reserves memory for different RTCS parameters and initializes the TCP/IP task.

Each project (server and client) contains an RTCS.c file which contains the initialize networking function with the RTCS configuration.

 

 

  1. Set the RTCS IP address to the device after initialization.

The main.h files have the macros and variables that store the IP parameters. You can change the IP address according your needs.

In RTCS.c files,  the following code sets the address, mask, gateway and server IP addresses.

ip_addr = IPADDR(A,B,C,D);

phy_addr = BSP_DEFAULT_ENET_DEVICE;

.

.

.

ip_data.ip = ip_addr;

ip_data.mask = ENET_IPMASK;

ip_data.gateway = 0;

 

 

  1. Calculate the MAC address for the device using the variables.

Use the ENET_get_mac_address() function to build a valid MAC address for the application. MAC address calculation takes the device number and IP address as parameters, and returns a valid MAC address in the IPCFG_default_enet_address variable.

 

  1. Initialize the Ethernet device available in the board with the calculated MAC address.

Use the ipcfg_init_device() function to tell the RTCS task what Ethernet device should be used and to set the calculated MAC address to that device. Once the MAC address is set and the device is initialized, it is possible to bind the device to the IP address.

error = ipcfg_init_device (phy_addr, serverAddress);


 

 

  1. After Ethernet device initialization, bind the device to the IP address and it is ready to communicate.

/* If DHCP Enabled, get IP address from DHCP server */

             if (dhcp) {

                    printf("\nDHCP bind ... ");

                    error = ipcfg_bind_dhcp_wait(phy_addr, 1, &ip_data);

                    if (error != IPCFG_ERROR_OK) {

                           printf("Error %08x!\n", error);

                    }

                    else {

                           printf("Successful!\n");

                    }

             } else {

       /* Else bind with static IP */

                    printf ("\nStatic IP bind ... ");

                    error = ipcfg_bind_staticip(phy_addr, &ip_data);

 

                    if (error != IPCFG_ERROR_OK) {

                           printf("Error %08x!\n",error);

                    }

                    else {

                           printf("Successful!\n");

                    }

             }

 

 

SERVER IMPLEMENTATION

            

For the server implementation, MQX uses a socket structure that is created and filled in this way:

laddr.sin_family      = AF_INET;

laddr.sin_port        = CONNECT_PORT;

laddr.sin_addr.s_addr = INADDR_ANY;

 

The socket() function creates an unbound socket in a communications domain. This function also returns a handler used in later function calls that operate on sockets.

/* Listen on TCP port */

listensock = socket(PF_INET, SOCK_STREAM, 0);

if (listensock == RTCS_SOCKET_ERROR)

{

error = RTCSERR_OUT_OF_SOCKETS;

}

 

The bind() function assigns a local socket address to a socket and the listen() function marks a socket as accepting connections.

error = bind(listensock, &laddr, sizeof(laddr));

if (!error)

{

       error = listen(listensock, 0);

}

 

The accept() function extracts the first connection on the queue of pending connections, creates a new socket with the same socket type protocol and address family as the specified socket, and allocates a new file descriptor for that socket.

child_sock = accept(listensock, NULL, NULL);

 

The recv() function receives a message from a socket.

error = recv(sock, (void *)cRecvBuff, sizeof(cRecvBuff), MSG_WAITALL);

                   

The send() function initiates transmission of a message from the specified socket to its peer. The send() function sends a message only when the socket is connected.

error= send(sock, (void *)cRecvBuff, sizeof(cRecvBuff), 0);

 

 

The messages received are checked in order to toggle a LED or shutdown the connection.

while(1)

       {

             error = recv(sock, (void *)cRecvBuff, sizeof(cRecvBuff), MSG_WAITALL);

             printf("Received: %s\n", cRecvBuff);

             if (error == RTCS_ERROR)

             {

                    printf("There was an error code %lx\n", RTCS_geterror(sock));

                    shutdown(sock, FLAG_CLOSE_TX);

                    return;

             }

             if(cRecvBuff[0]=='T')

             {

                    printf("Received: %s\n", cRecvBuff);

                    printf("LED was toggled from child\r\n");

                    lwgpio_toggle_value(&led1);

             }

             if(cRecvBuff[0]=='G')

             {                         

                    printf("Received: %s\n", cRecvBuff);

                    printf("Shutting down connection\n");

                    shutdown(sock,FLAG_CLOSE_TX);

                    _time_delay(2000); 

                    _task_abort(MQX_NULL_TASK_ID);

             }    

       }           

CLIENT IMPLEMENTATION

 

For the client implementation, it uses a socket structure that is created and filled in this way:

addr.sin_family      = AF_INET;

addr.sin_port        = DESTPORT;

addr.sin_addr.s_addr = IPADDR(192,168,1,200); //Server address

 

The socket() function creates an unbound socket.

sock = socket(PF_INET, SOCK_STREAM, 0);

 

 

The connect() function attempts to make a connection on a socket.

error = connect(sock, &addr, sizeof(addr));

      

The recv() function receives a message from a socket.

error= recv(sock, (void *)cReadBuff, sizeof(cReadBuff), 0);

      

 

The send() function sends a message only when the socket is connected (including when the peer of a connectionless socket has been set via connect() function).

error = send(sock, (void *)cReadBuff, sizeof(cReadBuff), 0);

      

 

In addition the client example can toggle a LED in the server board or destroy the socket.

/*****Infinite loop waiting for user to push a button***/

while(1){

       if(lwgpio_get_value(&btn1) == LWGPIO_VALUE_LOW)

       {

             _time_delay(150);

             sprintf((char *)cReadBuff, "Toggle from client2\n");

             printf("Sending: %s", cReadBuff);

             error = send(sock, (void *)cReadBuff, sizeof(cReadBuff), 0);

             if (error == RTCS_ERROR)

             {

                    printf("There was an error trying to send to the server\n");

                    return;

             }

       }

       if(lwgpio_get_value(&btn2) == LWGPIO_VALUE_LOW)

       {

             _time_delay(150);

             sprintf((char *)cReadBuff, "GoodBye\n");

             printf("Sending: %s", cReadBuff);

             error = send(sock, (void *)cReadBuff, sizeof(cReadBuff), 0);

             if (error == RTCS_ERROR)

             {

                    printf("There was an error trying to send to the server\n");

                    return;

             }

             printf("Shutting down connection\n");

             shutdown(sock,FLAG_CLOSE_TX);

             _task_abort(MQX_NULL_TASK_ID);

       }

 

 

 

I hope this helps,

Soledad

Outcomes