I did some tests:
int main(int argc, char** argv)
{
sf::TcpListener listener;
sf::Socket::Status status = listener.Listen(3456);
alwaysAssert(status == sf::Socket::Done);
sf::Thread thread([&]()
{
sf::TcpSocket socket;
sf::Socket::Status status = listener.Accept(socket);
alwaysAssert(status == sf::Socket::Done);
std::size_t receivedLen;
char buffer[10000];
while(true)
{
socket.Receive(buffer, sizeof(buffer), receivedLen);
}
});
thread.Launch();
sf::TcpSocket socket;
status = socket.Connect("127.0.0.1", 3456);
alwaysAssert(status == sf::Socket::Done);
sf::Packet toSend;
toSend << "hello";
const char * const msg = "1234hello";
unsigned int len = strlen(msg);
for(int i = 0; i < 20; ++i)
{
sf::Clock clock;
for(int i = 0; i < 100000; ++i)
{
status = socket.Send(toSend);
alwaysAssert(status == sf::Socket::Done);
}
unsigned int elapsed = clock.GetElapsedTime();
cout << "Duration with packet: " << elapsed << " ms" << endl;
//give the network time to stabilize
sf::Sleep(10000);
clock.Reset();
for(int i = 0; i < 100000; ++i)
{
status = socket.Send(msg, len);
alwaysAssert(status == sf::Socket::Done);
}
elapsed = clock.GetElapsedTime();
cout << "Duration without packet: " << elapsed << " ms" << endl;
//give the network time to stabilize
sf::Sleep(10000);
}
thread.Terminate();
return 0;
}
I forwarded the output to a textfile and started it in release mode.
The output is this:
Duration with packet: 17732 ms
Duration without packet: 8257 ms
Duration with packet: 17495 ms
Duration without packet: 9239 ms
Duration with packet: 17827 ms
Duration without packet: 8324 ms
Duration with packet: 16481 ms
Duration without packet: 8103 ms
Duration with packet: 16720 ms
Duration without packet: 8155 ms
Duration with packet: 16290 ms
Duration without packet: 8158 ms
Duration with packet: 16321 ms
Duration without packet: 8132 ms
Duration with packet: 16337 ms
Duration without packet: 8162 ms
Duration with packet: 16294 ms
Duration without packet: 8168 ms
Duration with packet: 16403 ms
Duration without packet: 8187 ms
Duration with packet: 16337 ms
Duration without packet: 8132 ms
Duration with packet: 16388 ms
Duration without packet: 8074 ms
Duration with packet: 16714 ms
Duration without packet: 8167 ms
Duration with packet: 16321 ms
Duration without packet: 8533 ms
Duration with packet: 16336 ms
Duration without packet: 8184 ms
Duration with packet: 16331 ms
Duration without packet: 8140 ms
Duration with packet: 16310 ms
Duration without packet: 8157 ms
Duration with packet: 16260 ms
Duration without packet: 8357 ms
Duration with packet: 16418 ms
Duration without packet: 8129 ms
Duration with packet: 16191 ms
Duration without packet: 8080 ms
This shows that when testing locally with very small messages, using sf::Packet takes about twice the time then sending without sf::Packet.
I'm quite sure that it's because of 2 packets being sent instead of one.
Does this convince you, or do I need to do more? ^^
Here is also a possible solution:
When sending a packet you first make sure that the vector is large enough to store 4 additional bytes (for the size).
Then you use std::memmov to move the data 4 bytes to the right.
Then you write the size at the first 4 bytes.
Then you use the Send overload which takes raw bytes.
Then you use memmove again to revert the change.
I have 2 more questions:
- Why are you always using resize when something is written to a packet? If the standard-library implementation allocates exactly the size you request and no more then you need to reallocate for every write. Maybe it would be better to allocate more than is needed.
- When having an non-blocking socket and doing a sent, must the buffer which is sent then be unchanged until the operation is completed?
For example if I do:
char buffer[1024];
socket.Send(buffer, sizeof(buffer));
buffer[1023] = 'a';
Can the change to the buffer then affect what actually is sent?
With boost::asio this can happen, but it also tells you when the operation is completed.