Sockets can now handle properly the situation where the packet size is received in multiple chunks

git-svn-id: https://sfml.svn.sourceforge.net/svnroot/sfml/trunk@1433 4e206d99-4929-0410-ac5d-dfc041789085
This commit is contained in:
LaurentGom 2010-03-02 12:00:12 +00:00
parent 4a840d4f48
commit 786408c5bc
4 changed files with 36 additions and 19 deletions

View File

@ -214,8 +214,10 @@ private :
// Member data // Member data
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SocketHelper::SocketType mySocket; ///< Socket descriptor SocketHelper::SocketType mySocket; ///< Socket descriptor
std::vector<char> myPendingPacket; ///< Data of the current pending packet, if any (in non-blocking mode) Uint32 myPendingHeader; ///< Data of the current pending packet header, if any
Int32 myPendingPacketSize; ///< Size of the current pending packet, if any (in non-blocking mode) Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any
std::vector<char> myPendingPacket; ///< Data of the current pending packet, if any
Int32 myPendingPacketSize; ///< Size of the current pending packet, if any
bool myIsBlocking; ///< Is the socket blocking or non-blocking ? bool myIsBlocking; ///< Is the socket blocking or non-blocking ?
}; };

View File

@ -215,8 +215,10 @@ private :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
SocketHelper::SocketType mySocket; ///< Socket identifier SocketHelper::SocketType mySocket; ///< Socket identifier
unsigned short myPort; ///< Port to which the socket is bound unsigned short myPort; ///< Port to which the socket is bound
std::vector<char> myPendingPacket; ///< Data of the current pending packet, if any (in non-blocking mode) Uint32 myPendingHeader; ///< Data of the current pending packet header, if any
Int32 myPendingPacketSize; ///< Size of the current pending packet, if any (in non-blocking mode) Uint32 myPendingHeaderSize; ///< Size of the current pending packet header, if any
std::vector<char> myPendingPacket; ///< Data of the current pending packet, if any
Int32 myPendingPacketSize; ///< Size of the current pending packet, if any
bool myIsBlocking; ///< Is the socket blocking or non-blocking ? bool myIsBlocking; ///< Is the socket blocking or non-blocking ?
}; };

View File

@ -344,11 +344,20 @@ Socket::Status SocketTCP::Receive(Packet& PacketToReceive)
std::size_t Received = 0; std::size_t Received = 0;
if (myPendingPacketSize < 0) if (myPendingPacketSize < 0)
{ {
Socket::Status Status = Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received); // Loop until we've received the entire size of the packet
if (Status != Socket::Done) // (even a 4 bytes variable may be received in more than one call)
return Status; while (myPendingHeaderSize < sizeof(myPendingHeader))
{
char* Data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize;
Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received);
myPendingHeaderSize += Received;
PacketSize = ntohl(PacketSize); if (Status != Socket::Done)
return Status;
}
PacketSize = ntohl(myPendingHeader);
myPendingHeaderSize = 0;
} }
else else
{ {
@ -472,6 +481,7 @@ void SocketTCP::Create(SocketHelper::SocketType Descriptor)
myIsBlocking = true; myIsBlocking = true;
// Reset the pending packet // Reset the pending packet
myPendingHeaderSize = 0;
myPendingPacket.clear(); myPendingPacket.clear();
myPendingPacketSize = -1; myPendingPacketSize = -1;

View File

@ -244,20 +244,25 @@ Socket::Status SocketUDP::Send(Packet& PacketToSend, const IPAddress& Address, u
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address, unsigned short& Port) Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address, unsigned short& Port)
{ {
// This is not safe at all, as data can be lost, duplicated, or arrive in a different order.
// So if a packet is split into more than one chunk, nobody knows what could happen...
// Conclusion : we shouldn't use packets with UDP, unless we build a more complex protocol on top of it.
// We start by getting the size of the incoming packet // We start by getting the size of the incoming packet
Uint32 PacketSize = 0; Uint32 PacketSize = 0;
std::size_t Received = 0; std::size_t Received = 0;
if (myPendingPacketSize < 0) if (myPendingPacketSize < 0)
{ {
Socket::Status Status = Receive(reinterpret_cast<char*>(&PacketSize), sizeof(PacketSize), Received, Address, Port); // Loop until we've received the entire size of the packet
if (Status != Socket::Done) // (even a 4 bytes variable may be received in more than one call)
return Status; while (myPendingHeaderSize < sizeof(myPendingHeader))
{
char* Data = reinterpret_cast<char*>(&myPendingHeader) + myPendingHeaderSize;
Socket::Status Status = Receive(Data, sizeof(myPendingHeader) - myPendingHeaderSize, Received, Address, Port);
myPendingHeaderSize += Received;
PacketSize = ntohl(PacketSize); if (Status != Socket::Done)
return Status;
}
PacketSize = ntohl(myPendingHeader);
myPendingHeaderSize = 0;
} }
else else
{ {
@ -265,9 +270,6 @@ Socket::Status SocketUDP::Receive(Packet& PacketToReceive, IPAddress& Address, u
PacketSize = myPendingPacketSize; PacketSize = myPendingPacketSize;
} }
// Clear the user packet
PacketToReceive.Clear();
// Use another address instance for receiving the packet data ; // Use another address instance for receiving the packet data ;
// chunks of data coming from a different sender will be discarded (and lost...) // chunks of data coming from a different sender will be discarded (and lost...)
IPAddress Sender; IPAddress Sender;
@ -402,6 +404,7 @@ void SocketUDP::Create(SocketHelper::SocketType Descriptor)
myPort = 0; myPort = 0;
// Reset the pending packet // Reset the pending packet
myPendingHeaderSize = 0;
myPendingPacket.clear(); myPendingPacket.clear();
myPendingPacketSize = -1; myPendingPacketSize = -1;