But as far as free code goes, there probably isn't anything better.
Quite possible.
I have looked at
FNET, because
vjmuzik has an Arduino library (
FNET fork and
NativeEthernet) for use with Teensy, which is more to my liking, but I haven't really used it in anger either. Teensy 4.1 is the only MCU I currently have with a 10/100 Ethernet on it. (I do have several different SBCs running Linux, and I can do zero-copy network I/O in Linux using memory-mapped tx and rx buffers, but that's different: the kernel does all the hard, complex stuff there.)
An interesting point relating to this is whether LWIP (or how much of it) is zero-copy.
True.
I've done lots of
MPI stuff, and particularly like the asynchronous I/O interface. It has very similar requirements as zero-copy, in that one must not modify the data buffer until the async operation completes. (Most implementations use a dedicated I/O thread handling the transfers in non-blocking mode.)
Compared to the socket interface, a zero-copy would really need a completely different interface, one where a write/send either takes a callback or closure, or returns a token, so that the buffer is retained until the operation completes (by the IP stack doing the callback, or updating the token state). Similarly, a read/receive should really be event-based, with a similar token or closure to tell the IP stack the data is no longer needed.
If I had to support zero-copy on Berkeley/POSIX sockets -type interface, I'd cry: it really isn't suitable for the task.
At minimum, I'd like to separate the header part and the payload part. Although they would be contiguous in received messages, having them separate in the API, and separate when sending messages –– especially if you could do a scatter-send with multiple recipients, the stack duplicating the data internally as needed –– would make a lot of sense. (The completion tracking would then be per header, not per data.)
Unfortunately, even in MPI, using
MPI_Isend() and
MPI_Irecv() for "zero-copy"/nonblocking/asynchronous I/O, seem to be extremely hard for many programmers to understand. I've even had heated arguments with "MPI Experts" who claim that using these is inherently
dangerous (because they just didn't understand how to use them properly). It isn't, and is the only way to allow a HPC distributed simulator/calculator to both compute and communicate simultaneously, not wasting time.
At the core, they behave just like zero-copy async sends and receives: the call returns immediately, but the data is read from the buffer or written to the buffer at some point in the future, and one needs to check the state of the request object to determine whether it succeeded or not. (I don't like that, I'd much prefer to have a callback/closure/event instead.) So, having dealt with the confusion, I'm not at all surprised that zero-copy I/O interfaces are "hard", when even something as stable and widely used as MPI confuses the "experts".
In IP stacks, the layered
OSI model confuses full-stack developers even more, because it takes a lot of experience and a robust personality to understand that such models are abstract, and do not need to –– should not –– reflect the actual API or implementation. (Saying that out aloud among network software developers would normally start a shouting match, too.. I got some really unpopular views! But I do try to explain what my views and opinions are based on, so that one can check if they have a reason to agree or disagree.)