Skip to main content
JDWBE
Associate III
August 23, 2026
Question

How to handle “Big TCP” packets in LwIP

  • August 23, 2026
  • 3 replies
  • 83 views

Hello forum members

I’m busy with the implementation of a TCP server that needs to handle a TCP connection with already existing PC application that I can’t change.

Everything works well as long the packets are not longer then 1500 bytes. When the packets are longer than this “magic number” LwIP is separating the packets in more than 1 piece. Is there a way to know the original length of the original packet?

See print screen Wireshark: Packet with length: 1876.

Debug from the controller:

First read:

 Second read:

How can I detect that these 2 reads (netconn_recv) are 1 packet? Instead of 2. I use the NETCONN API.

The connection is made at the beginning and never closed during the executing of the PC application.

 

Kind Regards 

3 replies

Graduate
August 24, 2026

Hi,

The MTU is around 1500 bytes, which means the maximum size of the Ethernet frame cannot exceed that. Therefore, a TCP packet larger than this, like in your example, is split into smaller packets, to fit inside the MTU.

Are you using a known protocol on top of TCP (HTTP, MQTT, etc.)? Or is it just raw TCP? Normally, if it would be raw TCP (a custom protocol), you would have to implement the message framing by yourself, more precisely marking the beginning and end of each packet and parsing the packet.

As an example, using the Mongoose Networking Library on top of LWIP (example for STM32 here) you could handle either case in the user event handler.

For a customer protocol, you would do something like this:

static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_READ) {
long n = *(long *) ev_data;

printf("new bytes: %ld\n", n);
printf("total buffered: %zu\n", c->recv.len);

// Todo: parse whatever complete messages exist in c->recv

// Once N bytes have been processed, clean the receive buffer
// mg_iobuf_del(&c->recv, 0, N);
}
}

In the case of a known protocol, such as HTTP, Mongoose buffers the whole TCP data until the entire message has been received, so in the user handler, you would get the entire packet, regardless of how many frames it consists of. The handler would look like this (more on how Mongoose works and its event handlers here):

static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
struct mg_http_message *hm = ev_data;

// full HTTP request is available here
printf("body size: %lu\n", hm->body.len);
}
}

These examples are as a guidance, I think Netconn API should have something similar like Mongoose has, though I am not familiar with netconn.

JDWBE
JDWBEAuthor
Associate III
August 24, 2026

Hi 

Thanks for your answer. In was wondering that i forgot something how to get the total length for spitted package.

Well a protocol, not really,  it is uart communication collected in a TCP stream, it can contain one command, but also multiple commands and also the start from an command and the other data can fit inside other TCP packet(s), the max size that i already found was 12K. There is also no documentation. This makes it very hard to write the software that works, always.

 

Graduate
August 24, 2026

Ideally, you would want to have an application protocol on top of TCP to frame that byte stream. With raw TCP alone, it’s almost impossible to know the boundaries of each message.

A simple example would be this: each message starts with a header containing the message length. You read the header and get the message length, then keeps reading from the TCP stream until you’ve  received the specified number of bytes. That makes the stream much easier to parse.

Though I understand that you can’t control the sender, the PC application, so you have no control of the message framing. Perhaps there are some useful headers/commands, like you mentioned, and you should use those to establish the boundaries of each message. If you manage this, then the issue should be solved.