cancel
Showing results for 
Search instead for 
Did you mean: 

HTTP server example based on LWIP netconn

DRude.1
Associate II

Hi, I create a project on stm32f746 nucleo board using LWIP stack (netconn) and FreeRTOS.

The main function of this project is HTTP server. But I have a few problems with this functionality - they are errors of connection and close states of HTTP session.

Have anybody working project of HTTP server (netconn) which can make a good connection without errors, RST, retransmissions? I am needed a code of stability working server because tested a lot of codes, but all of its works not perfect.

Maybe I did a mistake in this code?

Code which I use:

typedef struct struct_sock_t {
  struct netconn *conn;
} struct_sock;
struct_sock sock;
 
void StartDefaultTask(void const * argument)
{
  /* init code for LWIP */
  MX_LWIP_Init();
  /* USER CODE BEGIN 5 */
  //-----------------------------------------------------------
  struct netconn *conn;
  err_t err;
 
  conn = netconn_new(NETCONN_TCP);
  if(conn!=NULL)
  {
	  sock.conn = conn;
	  err = netconn_bind(conn, NULL, 80);
	  if(err == ERR_OK)
	  {
		  netconn_listen(conn);
		  sys_thread_new("tcp_thread", tcp_thread, (void*)&sock, DEFAULT_THREAD_STACKSIZE, osPriorityNormal);
	  }
	  else
	  {
		  netconn_delete(conn);
		  HAL_GPIO_WritePin(GPIOG, GPIO_PIN_7, GPIO_PIN_SET);             // LED RED
	  }
  }
  for(;;)
  {
	  osDelay(1);
  }
  //-----------------------------------------------------------
  /* USER CODE END 5 */
}
static void tcp_thread(void *arg)
{
	err_t recv_err;                      // Variables for arguments (errors)
	err_t err;                           // Variables for arguments (errors)
	struct netconn *conn;                // Structure for connection
	struct netconn *newconn;             // Structure for connection
	struct netbuf *inbuf;                // Pointer to connection buffer
	struct_sock *arg_sock;               // Pointer to arguments of task
	arg_sock = (struct_sock*) arg;
	conn = arg_sock->conn;
	u16_t buflen;
	char* buf;
	struct fs_file file;
	for(;;)
	{
		err = netconn_accept(conn, &newconn);
	    if (err == ERR_OK)
	    {
	    	recv_err = netconn_recv(newconn, &inbuf);                     // Receiving the socket data in inbuf
		    if (recv_err == ERR_OK)
		    {
		    	if (netconn_err(newconn) == ERR_OK)
		    	{
		    		netbuf_data(inbuf, (void**)&buf, &buflen);
		    	    if ((buflen >=5) && (strncmp(buf, "GET /", 5) == 0))
		    	    {
		    	    	if ((strncmp((char const *)buf,"GET / ",6)==0)||(strncmp((char const *)buf,"GET /index.html",15)==0))
		    	    	{
		    	    		fs_open(&file, "/index.html");
		    	    		netconn_write(newconn, (const unsigned char*)(file.data), (size_t)file.len, NETCONN_NOCOPY);
		    	    		fs_close(&file);
		    	    	}
		    	    	else if (strncmp((char const *)buf,"GET /IMG/Test.png",17)==0)
		    	    	{
		    	    		fs_open(&file, "/IMG/Test.png");
		    	    		netconn_write(newconn, (const unsigned char*)(file.data), (size_t)file.len, NETCONN_NOCOPY);
		    	    		fs_close(&file);
		    	    	}
		    	    	else
		    	    	{
		    	    		fs_open(&file, "/404.html");
		    	    		netconn_write(newconn, (const unsigned char*)(file.data), (size_t)file.len, NETCONN_NOCOPY);
		    	    		fs_close(&file);
		    	    	}
		    	    }
		    	    else
		    	    {
		    	    	osDelay(1);
		    	    }
		    	}
		    	else
		    	{
		    		osDelay(1);
		    	}
		    }
		    netbuf_delete(inbuf);
		    netconn_close(newconn);
		    netconn_delete(newconn);
	    }
	    else
	    {
	    	osDelay(1);
	    }
	}
}

0693W00000AMsplQAD.png0693W00000AMspbQAD.png

1 ACCEPTED SOLUTION

Accepted Solutions

Hello @DRude.1​ ,

Updating the graph every second using post or get would be too heavy. Using WebSockets should help in this regard (a single continuous TCP connection, see this for some inspiration https://github.com/RealTimeLogic/MinnowServer).

Otherwise, it is possible to increase the maximum number of simultaneous connections using the MEMP_NUM_TCP_PCB macro, but it would use more memory and processor.

To ensure that connections are closed automatically after a certain timeout, you can follow this steps in this link: https://lwip.fandom.com/wiki/Netconn_receive_timeout

Finally, compressing the data that you're transmitting (something simple like differential compression) and relaxing some of the real-time constraints that you have (I don't know about your particular application, but using Bezier curves to interpolate between the samples thus reducing the throughput) should also help.

Best regards,

Walid

View solution in original post

10 REPLIES 10

Hello @DRude.1​ ,

Too many retransmissions and RST packets usually indicate a packet loss issue.

From the Wireshark trace, it seems that the board (192.168.1.195) is not the cause of retransmissions. Perhaps setting the HTTP clients timeout to something more forgiving would reduce them.

Otherwise, generally speaking, there does not seem to be an issue as the communication proceeds normally and is closed normally too. The traces don't look bad at all after all.

Could you please describe your setup?

Best Regards,

Walid

Pavel A.
Evangelist III

If you have FreeRTOS you may want to use their network library and driver instead of LwIP.

https://github.com/FreeRTOS/FreeRTOS-Plus-TCP

It should work well with FreeRTOS :)

-- p

Hi @Walid ZRELLI​, I changed now the code of my HTPP server and added AJAX (it's for sending data array to HTTP client (browser) and building a chart of this array). So I have a couple of problems now. The first is a big delay with the renovation of the chart(It must be once to second because the client sends GET requests every 1000 msec) but in reality the chart brake and renovation once to 5-30 seconds. And the second one is a lot of RST/RST,ACK HTTP packages. So I feel like for everyone GET request the server creates a new connection, but do not close it.

Added to code

                        else if (strncmp((char const *)buf,"GET /js/Chart.min.js",20)==0)
                        {
                            fs_open(&file, "/js/Chart.min.js");
                            netconn_write(newconn, (const unsigned char*)(file.data), (size_t)file.len, NETCONN_NOCOPY);
                            fs_close(&file);
                        }                        
                       else if (strncmp((char const *)buf,"GET /content.bin",16)==0)
                        {
                            DynWebPage(newconn, arg_sock->y_pos);
                        }

Where DynWebPage generator of random number. It is just for example

void DynWebPage(struct netconn *conn, uint16_t y_pos)
{
  portCHAR PAGE_BODY[1300];
  uint16_t len = 0;
  int i;
  PAGE_BODY[0] = 0;
  int val = 0;
  sprintf(PAGE_BODY,"%s%s%s%s%drn%s",PAGE_HEADER_200_OK,PAGE_HEADER_SERVER,PAGE_HEADER_CONTENT_STREAM,PAGE_HEADER_LEN,1024,PAGE_HEADER_BYTES);
  len = strlen(PAGE_BODY);
  for(i=0;i<512;i++)
  {
      val = HAL_RNG_GetRandomNumber(&hrng)%4096;
      PAGE_BODY[len + i * 2] = (uint8_t)val;
      PAGE_BODY[len + i * 2 + 1] = (uint8_t)(val>>8);
  }
  netconn_write(conn, PAGE_BODY, strlen((char*)PAGE_BODY) + 1024, NETCONN_COPY);
}

And a example of Wireshark session. Also I can show html code of server

0693W00000ANgOzQAL.png0693W00000ANgOuQAL.pngI use stm32f746 Nucleo board and PC (Google Chrome) with direct connection

@Pavel A.​ I lost a lot of time creating TCP and HTTP server with LWIP and It works almost well, I do not want to study something another, I prepare to fix what I have now. But thanks for advice

Hello @DRude.1​ ,

Updating the graph every second using post or get would be too heavy. Using WebSockets should help in this regard (a single continuous TCP connection, see this for some inspiration https://github.com/RealTimeLogic/MinnowServer).

Otherwise, it is possible to increase the maximum number of simultaneous connections using the MEMP_NUM_TCP_PCB macro, but it would use more memory and processor.

To ensure that connections are closed automatically after a certain timeout, you can follow this steps in this link: https://lwip.fandom.com/wiki/Netconn_receive_timeout

Finally, compressing the data that you're transmitting (something simple like differential compression) and relaxing some of the real-time constraints that you have (I don't know about your particular application, but using Bezier curves to interpolate between the samples thus reducing the throughput) should also help.

Best regards,

Walid

Piranha
Chief II

> a good connection without errors, RST, retransmissions?

https://community.st.com/s/question/0D50X0000BOtfhnSQB/how-to-make-ethernet-and-lwip-working-on-stm32

Also I can add that lwIP is significantly more flexible and can perform much better compared to +TCP stack from FreeRTOS.

@Piranha​ I saw your work about LWIP, but without program code support I can not apply it

And I thought you are a developer... Well, for Cube clickers the answer is simple - no, noone has gotten ST's network implementation working reliably because the HAL/Cube code is a broken bloatware written by incompetent "experts". You can write the code yourself, hire an actual developer, who can write code, or try some platform like ARM Mbed, ChibiOS. No other way around. Everything else is just marketing lies and fantasy.

Do Chibios or mbed have good ethernet drivers for STM32?