M52259 RTCS TCP/IP server allowing multiple client socket connections

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

M52259 RTCS TCP/IP server allowing multiple client socket connections

Jump to solution
2,254 Views
matthewteolis
Contributor I

Hi,

I would like to be able to have a Server running on the M52259EVB chip that will accept multiple TCP/IP socket connections, preferably on the same port (if possible). I have posted the code showing what I'm doing and I would like to know what's wrong with my code. Thank you.

My environment:

  • MQX 3.4
  • CodeWarrior 7.1
  • M52259EVB
  • Java, for client application connecting with sockets

Problems:

  1. I currently can't connect 2 clients on the M52259EVB server.
  2. I can only connect/disconnect 5 times. On the 6th time, WireShark shows TCP Retransmission and I can't connect to my board anymore unless I restart the board.

/*

** ****************

** Library includes

** ****************

*/

#include < mqx.h >

#include < bsp.h >

#include < rtcs.h >

#include < ipcfg.h >

#include < string.h >

/*

** ****************

** Project includes

** ****************

*/

#include "ProjectInclude.h"

#include "Initializations.h"

/*

** **************************

** Local functions prototypes

** **************************

*/

void InitRTCS()

{

    IPCFG_IP_ADDRESS_DATA ip_data;

    _enet_address mac_address;

    uint_32 error;

    // For multi socket connection (doesn't work)

    _RTCSPCB_init = 4;

    _RTCSPCB_grow = 2;

    _RTCSPCB_max = 20;

    _RTCS_msgpool_init = 4;

    _RTCS_msgpool_grow = 2;

    _RTCS_msgpool_max = 20;

    _RTCS_socket_part_init = 4;

    _RTCS_socket_part_grow = 2;

    _RTCS_socket_part_max = 20;

    error = RTCS_create();

    if (error != RTCS_OK)

    {

        printf("\n[TCPServer]: Failed to create RTCS");

        _task_block();

    }

    ip_data.ip = IPADDR(200, 200, 200, 200);

    ip_data.mask = IPADDR(255, 255, 255, 0);

    ip_data.gateway = IPADDR(0, 0, 0, 0);

    ENET_get_mac_address(BSP_DEFAULT_ENET_DEVICE, ip_data.ip, mac_address);

    ipcfg_init_device(BSP_DEFAULT_ENET_DEVICE, mac_address);

    error = ipcfg_bind_staticip(BSP_DEFAULT_ENET_DEVICE, & ip_data);

    if (error != RTCS_OK)

    {

        printf("\n[TCPServer]: Failed to bind static ip");

        _task_block();

    }

    else

    {

        _task_create(0, TCPS_MAIN_TASK, 0); // TCPServer()

    }

}

void TCPServer()

{

    uint_32 error;

    uint_32 sock, listensock;

    sockaddr_in addr, client;

    uint_16 client_len = sizeof(client);

    // Create a socket //

    listensock = socket(AF_INET, SOCK_STREAM, 0);

    if (listensock == RTCS_SOCKET_ERROR)

    {

        printf("\n[TCPServer]: Failed to create the stream socket.");

        _task_block();

    }

    addr.sin_family = AF_INET;

    addr.sin_port = 17;

    addr.sin_addr.s_addr = INADDR_ANY;

    // Bind the socket //

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

    if (error == RTCS_ERROR)

    {

        printf("\n[TCPServer]: Failed to bind the stream socket - 0x%lx", error);

        _task_block();

    }

    // Start listening //

    error = listen(listensock, 0);

    if (error == RTCS_ERROR)

    {

        printf("\n[TCPServer]: listen() failed - 0x%lx", error);

        _task_block();

    }

    while (1)

    {

        // Accept the connection //

        sock = accept(listensock, & client, & client_len);

        if (sock != RTCS_SOCKET_ERROR)

        {

            // Create sub thread to service client's request //

            _task_create(0, TCPS_COMM_TASK, sock); // TCPCommunication()

        }

        else

        {

            error = RTCS_geterror(listensock);

            // ? When will accept return RTCS_SOCKET_ERROR & RTCS_OK ?

            if (error == RTCS_OK)

            {

                shutdown(listensock, FLAG_ABORT_CONNECTION);

                printf("\n[TCPServer]: Connection reset by peer.");

                printf("\n[TCPServer]: Closed.");

                break;

            }

            else

            {

                printf("\n[TCPServer]: Failed to accept, CODE = 0x%x", error);

                _task_block();

            }

        }

    }

}

void TCPCommunication(uint_32 temp)

{

    uint_32 error;

    uint_8 recv_buffer[54];

    uint_32 sock = temp;

    uint_32 opt_val;

    uint_32 opt_len;

    // set receive push to FALSE, recv will return only if buffer is full, and timeout if set.

    //opt_val = FALSE;

    opt_val = TRUE;

    opt_len = sizeof(uint_32);

    error = setsockopt(sock, SOL_TCP, OPT_RECEIVE_PUSH, & opt_val, opt_len);

    if (error != RTCS_OK)

    {

        printf("\n[TCPServer]: Failed to setsockopt for OPT_RECEIVE_PUSH, CODE = 0x%x.", error);

        _task_block();

    }

    // set receive timeout to 60s, recv will return received n bytes if timeout occur

    opt_val = 60 * 1000;

    error = setsockopt(sock, SOL_TCP, OPT_RECEIVE_TIMEOUT, & opt_val, opt_len);

    if (error != RTCS_OK)

    {

        printf("\n[TCPServer]: Failed to setsockopt for OPT_RECEIVE_TIMEOUT, CODE = 0x%x.", error);

        _task_block();

    }

    opt_val = 54;

    error = setsockopt(sock, SOL_TCP, OPT_RBSIZE, & opt_val, opt_len);

    if (error != RTCS_OK)

    {

        printf("\n[TCPServer]: Failed to setsockopt for OPT_RBSIZE, CODE = 0x%x.", error);

        _task_block();

    }

    // Clean the buffers to '\0' //

    memset(recv_buffer, 0, 54);

    while (TRUE)

    {

        if (recv(sock, recv_buffer, 54, 0) == RTCS_ERROR)

        {

            error = RTCS_geterror(sock);

            // Close TCPServer if TCPClient close first.

            if (error == RTCSERR_TCP_CONN_CLOSING)

            {

                shutdown(sock, FLAG_ABORT_CONNECTION);

                printf("\n[TCPServer]: TCPClient Closed (Socket = 0x%x).", sock);

                break;

            }

            // Close TCPServer if TCPClient abort.

            else if (error == RTCSERR_TCP_CONN_RESET)

            {

                shutdown(sock, FLAG_ABORT_CONNECTION);

                printf("\n[TCPServer]: Connection reset by peer.");

                printf("\n[TCPServer]: TCPClient Closed (Socket = 0x%x).", sock);

                break;

            }

            // Timeout occur if zero char received.

            else if (error == RTCSERR_TCP_TIMED_OUT)

            {

                printf("\n[TCPServer]: recv Timeout.");

                if (send(sock, "TCPServer recv Timeout.", strlen("TCPServer recv Timeout.") + 1, 0) == RTCS_ERROR)

                {

                    printf("\n[TCPServer]: Failed to send, CODE = 0x%x.", RTCS_geterror(sock));

                    _task_block();

                }

            }

            else

            {

                printf("\n[TCPServer]: Failed to recv, CODE = 0x%x.", error);

                _task_block();

            }

        }

        else

        {

            if (send(sock, recv_buffer, sizeof(recv_buffer), 0) == RTCS_ERROR)

            {

                printf("\n[TCPServer]: Failed to send, CODE = 0x%x.", RTCS_geterror(sock));

                _task_block();

            }

            // clean buffer to ensure '\0' filled for next recv.

            memset(recv_buffer, 0, 54);

        }

    }

}

0 Kudos
1 Solution
1,265 Views
Luis_Garabo
NXP TechSupport
NXP TechSupport

Hi Matthew,

I believe that a Daemon server implementation is what you need here. Take a look to this thread for more details on it. Let me know if that solves your problem.

Re: Embedded server

Regards,
Garabo

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

View solution in original post

0 Kudos
8 Replies
1,266 Views
Luis_Garabo
NXP TechSupport
NXP TechSupport

Hi Matthew,

I believe that a Daemon server implementation is what you need here. Take a look to this thread for more details on it. Let me know if that solves your problem.

Re: Embedded server

Regards,
Garabo

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,265 Views
matthewteolis
Contributor I

Hi Garabo,

After testing the server I noticed that you can't connect to the server after x amount of connections.

Examples:

  • If you were to have 5 clients connect to the server, where a maximum of 5 sockets are available, trying to connect another client would halt the whole system.
  • If you were to have a maximum of 5 sockets available and you were to connect and disconnect 5 times are going to work fine. Although when attempting to connect for the 6th time, you wouldn't be able to.

Now I'm wondering what the problem could be because this bug applies to my code (when I used yours as reference) and when I put just your server (untouched, copy pasted) into the MCU.

Thanks

0 Kudos
1,265 Views
Luis_Garabo
NXP TechSupport
NXP TechSupport

Hi Matthew,

You most probably are getting out of memory. The child tasks are taking about 2K of stack each one. Also, each socket is consuming memory. I suggest taking a look to the "Stack Usage" option in MQX menu while you are debugging step by step when the client number 5 is connected. Reduce the stack until you are a 95% of utilization. Do not go higher than that. You need to leave space for the context switching memory allocation in your stack.

Let me know if that helps.


Have a great day,
Garabo

0 Kudos
1,265 Views
matthewteolis
Contributor I

Hi Garabo,

I'm also assuming that it is an out of memory error. Although even with your code it's not working (unable to connect after x - 2 connections, where x is the values passed in to your initialize_networking(x, x, x, 0) method). As in, if I put the value 2 for x, then you can't connect to the system. If I were to put 6 then I would have 4 connections successfully working and on the 5th the whole system stops.

Another problem is, we can't do step by step debugging. Would there be other ways to solve this problem?

Thanks

0 Kudos
1,265 Views
Luis_Garabo
NXP TechSupport
NXP TechSupport

Hi Matthew,

The behavior you are getting is correct. MQX is consuming 2 sockets for itself. Both are being used by the daemon server to accept the new connections. You always have to consider loosing two sockets from the ones you are defining. When I developed this code I was able to perform about 10 socket connections in my testings. you could start increasing the amount allowed. Don't worry, give X the size of 20, for instance. The memory won't be allocated until a connection is established. After this try as many connections as the memory allows. If you want more memory you can then use the MRAM in the M52259EVB to store other data, NOT the TCPIP please. The TCPIP, sockets, and all that should remain in the internal RAM.

Regarding debugging, well, it is not possible to debug TCPIP because of the timeouts running inside the stack. You can reach some break point but if you try to run from there you may not see the application working anymore, sockets may not be connected, etc. and then you need to restart the application. I suggest traces, like with printf() calls. This way you can see in the terminal your trace points and print the value of some variables.

Another thing you can do is to use wireshark tool (Wireshark · Go Deep.) to sniff the TCPIP packages from your LAN/PC/board.

I hope this helps.


Have a great day,
Garabo

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,265 Views
matthewteolis
Contributor I

Thank you Garabo, this worked!

0 Kudos
1,265 Views
soledad
NXP Employee
NXP Employee

Hello matthewteolis,

Please check the below application note, the objective of this appnote is to implement 4 clients that get a patient’s heart signal and heart rate through a MED-EKG development board and send it over Ethernet to a server. It is possible to increase the number of clients depending on the requirements and hardware availability.

http://cache.freescale.com/files/32bit/doc/app_note/AN4644.pdf

I hope this helps,


Have a great day,
Sol

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos
1,265 Views
matthewteolis
Contributor I

Hi soledad,

I've looked at the PDF and I don't see how it helps?

  • The application mentioned in the PDF uses UDP protocol, while I want to use TCP protocol.
  • I also want to know what's wrong with my code:
    • That makes it only accept one client at a time
    • That fails to connect to the MCU after 5 connections/disconnections (I connect, send data, receive data, and disconnect; this works 5 times. I then try to connect again and it fails. I have to restart the MCU in order to be able to connect to the unit again)

Would it be possible to get some code snippets (on a proper TCP server with multi-client functionality) or point out the errors in my code in order to get these problems fixed?

Thanks

0 Kudos