Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Problem when sending big paquet with TCP  (Read 3563 times)

0 Members and 1 Guest are viewing this topic.

arthuro

  • Newbie
  • *
  • Posts: 42
    • View Profile
    • Email
Problem when sending big paquet with TCP
« on: August 07, 2013, 02:08:48 pm »
Hi,

I have some troubles when I try to send big packet with TCP.

When packets are too big, sending status become sf::Status::Not_Ready regardless on how much time I sleep the program.
When the server have problem, the receiving status of the client still sf::Status::Done and I receive the same packet indefinitely.

I already post a topic on the SFML French forum here--> http://fr.sfml-dev.org/forums/index.php?topic=12537
Laurent advise me to ask it on the English forum.

Some details:
  • I use SFML 2.1
  • I use not blocking sockets    ( everything work with blocking sockets)
  • I use the localhost (127.0.0.1) and 2 instances of my applications to test.
  • I use Linux (Lubuntu)


I have done a minimal code that reproduce this problem:

The serveur sends packets. Packets grow up by multipling its size by 2 each time.
If the sending status is NotReady, the program sleep during a time which is multiplied by 2 each time.

The client receives each packets.

#include <SFML/Network.hpp>
#include <iostream>

void sendBigPaquet(int size, sf::TcpSocket& socket, int timeout=1)
{
        std::cout<<"sending paquet size="<<size;
        sf::Packet paquet;
        paquet<<sf::Uint32(size);
        for(int i=0;i<size;++i)
        {
                paquet<<sf::Uint32(0);
        }
        switch (socket.send(paquet))
        {
                case sf::Socket::Done:
                        std::cout<<" Status : Done"<<std::endl;
                        break;
                case sf::Socket::NotReady:
                        std::cout<<" Status : NotReady"<<std::endl;
                        std::cout<<"waiting "<<timeout<<" secondes"<<std::endl;
                        sf::sleep(sf::seconds(timeout));
                        sendBigPaquet(size,socket,timeout*2);
                        break;
                case sf::Socket::Disconnected:
                        std::cout<<" Status : Diconnected"<<std::endl;
                        break;
                case sf::Socket::Error:
                        std::cout<<" Status : Error"<<std::endl;
                        break;
        }
}

void receiveBigPaquet(sf::TcpSocket& socket)
{
        sf::Packet paquet;
        switch (socket.receive(paquet))
        {
                case sf::Socket::Done:
                        std::cout<<"Status : Done ";
                        sf::Uint32 size;
                        paquet>>size;  
                        std::cout<<"receiving paquet size = " << int(size)<<std::endl;
                        //for(int i=0;i<int(size);++i)
                        //{
                                //sf::Uint32 b;
                                //paquet>>b;
                        //}
                break;
               
                case sf::Socket::NotReady:
                        std::cout<<"Status : Not ready"<<std::endl;
                        break;

                case sf::Socket::Disconnected:
                        std::cout<<"Status : Disconnected"<<std::endl;
                        break;
               
                case sf::Socket::Error:
                        std::cout<<"Status : Error"<<std::endl;
                        break;
        }
}


int main(int argc, const char *argv[])
{
        std::cout<<"server(0) ou client(1)"<<std::endl;
        int server;
        std::cin>>server;
        std::cout<<"port:"<<std::endl;
        int port;
        std::cin>>port;

        if (server==0)
        {
                // Server
                sf::TcpListener serverListener;
                sf::TcpSocket socket;
               
                socket.setBlocking(false);
                serverListener.setBlocking(false);
       
                serverListener.listen(port);
                while (serverListener.accept(socket)!=sf::Socket::Done)
                                sf::sleep(sf::seconds(0.3));
               
               
                int size=1;
                for(;;)
                {
                        sendBigPaquet(size,socket);    
                        sf::sleep(sf::seconds(1.0));
                        size*=2;
                }

        }
        else
        {
                // client
                sf::TcpSocket socket;
               
                socket.setBlocking(false);
               
                while(socket.connect("127.0.0.1",port)!=sf::Socket::Done)
                        sf::sleep(sf::seconds(0.3));
               
                for(;;)
                {
                        receiveBigPaquet(socket);
                        sf::sleep(sf::seconds(0.3));
                }
        }
        return 0;
}
 

And that is what I get for the server
./main
server(0) ou client(1)
0
port:
2222
sending paquet size=1 Status : Done
sending paquet size=2 Status : Done
sending paquet size=4 Status : Done
sending paquet size=8 Status : Done
sending paquet size=16 Status : Done
sending paquet size=32 Status : Done
sending paquet size=64 Status : Done
sending paquet size=128 Status : Done
sending paquet size=256 Status : Done
sending paquet size=512 Status : Done
sending paquet size=1024 Status : Done
sending paquet size=2048 Status : Done
sending paquet size=4096 Status : Done
sending paquet size=8192 Status : Done
sending paquet size=16384 Status : Done
sending paquet size=32768 Status : Done
sending paquet size=65536 Status : Done
sending paquet size=131072 Status : Done
sending paquet size=262144 Status : Done
sending paquet size=524288 Status : Done
sending paquet size=1048576 Status : NotReady
waiting 1 secondes
sending paquet size=1048576 Status : NotReady
waiting 2 secondes
sending paquet size=1048576 Status : NotReady
waiting 4 secondes
sending paquet size=1048576 Status : NotReady
waiting 8 secondes
 


And for the client
./main
server(0) ou client(1)
1
port:
2222
Status : Done receiving paquet size = 1
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 2
Status : Not ready
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 4
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 8
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 16
Status : Not ready
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 32
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 64
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 128
Status : Not ready
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 256
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 512
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 1024
Status : Not ready
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 2048
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 4096
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 8192
Status : Not ready
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 16384
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 32768
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 65536
Status : Not ready
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 131072
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 262144
Status : Not ready
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 524288
Status : Not ready
Status : Not ready
Status : Not ready
Status : Not ready
Status : Not ready
Status : Not ready
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
Status : Done receiving paquet size = 1048576
 




Anybody has an idea ?
Thanks.
« Last Edit: August 07, 2013, 02:14:05 pm by arthuro »

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Problem when sending big paquet with TCP
« Reply #1 on: August 07, 2013, 07:27:58 pm »
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 :D.

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...
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

arthuro

  • Newbie
  • *
  • Posts: 42
    • View Profile
    • Email
Re: Problem when sending big paquet with TCP
« Reply #2 on: August 08, 2013, 12:39:28 pm »
Thanks you for this clear reply ;)

edit:
Sorry if I don't understand English well but you say that every packet I receive on client-side was the start of a big packet on server-side. But when the problem appear, I get ever and ever a packet every time I try to receive somethings and I receive many more packets than the server send. Thus the packet I receive isn't the packet I send but something else I don't understand. A problem caused by incomplete packet.
But okay for the Send problem.
« Last Edit: August 08, 2013, 02:22:53 pm by arthuro »