The problem is the way SFML sends data/packets. It concatenates the length of the packet onto the front of the data block and sends this using the byte-based send of the socket object. If you send such big packets, the TCP buffer might (most probably will) be full rather fast. Now comes the fun part: When SFML tries to send the data, it tells the operating system to queue the data block which i described above. This leads to the header as well as whatever else fits getting queued and the rest of the packet data being ignored. Because Laurent does this:
// Check for errors
if (sent < 0)
return priv::SocketImpl::getErrorStatus();
SFML ends up not checking for cases where not all the data is queued when the buffer is already relatively full. This means, if the packet could not be sent whole, SFML will interpret this as "oh look, absolutely no bytes were queued, so I can inform the user to try sending the whole packet again in the future". This leads to you retrying to send the same packet over and over and only having the first X bytes of it get queued all the time.
The funny thing is that on the receiver side, you will keep getting the correct amount of bytes, because the packet header always gets queued by the sender, and this is the only information SFML needs to dequeue that size of a packet. If you check the data for integrity however, you will notice that most of it is garbage
.
This was already discussed in a GitHub issue. SFML packets really shouldn't be used to fragment data. That is something they don't currently support, at least using non-blocking sockets since control is passed back to the user, and the send state is not saved anywhere. Even if you tried making your own packet class for this, you still won't be able to get the amount of bytes that were actually queued because SFML does not return this value.
I already recommended Laurent to change the signature of the send() method to this:
Socket::Status TcpSocket::send(const void* data, std::size_t size, std::size_t& sent)
to fit better with the receive() method and provide users who know what they are doing with the tools they need to use sockets effectively, even in non-blocking mode.
It is still strange to me, why in your receive application, the packet headers align perfectly with each receive() call. I might test this myself...