Added a way for partial sends over non-blocking TcpSockets to be handled properly.
This commit is contained in:
parent
67c7663c80
commit
d790114df8
@ -282,6 +282,7 @@ private:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
std::vector<char> m_data; ///< Data stored in the packet
|
std::vector<char> m_data; ///< Data stored in the packet
|
||||||
std::size_t m_readPos; ///< Current reading position in the packet
|
std::size_t m_readPos; ///< Current reading position in the packet
|
||||||
|
std::size_t m_sendPos; ///< Current send position in the packet (for handling partial sends)
|
||||||
bool m_isValid; ///< Reading state of the packet
|
bool m_isValid; ///< Reading state of the packet
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ public:
|
|||||||
{
|
{
|
||||||
Done, ///< The socket has sent / received the data
|
Done, ///< The socket has sent / received the data
|
||||||
NotReady, ///< The socket is not ready to send / receive data yet
|
NotReady, ///< The socket is not ready to send / receive data yet
|
||||||
|
Partial, ///< The socket sent a part of the data
|
||||||
Disconnected, ///< The TCP socket has been disconnected
|
Disconnected, ///< The TCP socket has been disconnected
|
||||||
Error ///< An unexpected error happened
|
Error ///< An unexpected error happened
|
||||||
};
|
};
|
||||||
|
@ -124,6 +124,9 @@ public:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Send raw data to the remote peer
|
/// \brief Send raw data to the remote peer
|
||||||
///
|
///
|
||||||
|
/// To be able to handle partial sends over non-blocking
|
||||||
|
/// sockets, use the send(const void*, std::size_t, std::size_t&)
|
||||||
|
/// overload instead.
|
||||||
/// This function will fail if the socket is not connected.
|
/// This function will fail if the socket is not connected.
|
||||||
///
|
///
|
||||||
/// \param data Pointer to the sequence of bytes to send
|
/// \param data Pointer to the sequence of bytes to send
|
||||||
@ -136,6 +139,22 @@ public:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Status send(const void* data, std::size_t size);
|
Status send(const void* data, std::size_t size);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
/// \brief Send raw data to the remote peer
|
||||||
|
///
|
||||||
|
/// This function will fail if the socket is not connected.
|
||||||
|
///
|
||||||
|
/// \param data Pointer to the sequence of bytes to send
|
||||||
|
/// \param size Number of bytes to send
|
||||||
|
/// \param sent The number of bytes sent will be written here
|
||||||
|
///
|
||||||
|
/// \return Status code
|
||||||
|
///
|
||||||
|
/// \see receive
|
||||||
|
///
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Status send(const void* data, std::size_t size, std::size_t& sent);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Receive raw data from the remote peer
|
/// \brief Receive raw data from the remote peer
|
||||||
///
|
///
|
||||||
@ -157,6 +176,10 @@ public:
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
/// \brief Send a formatted packet of data to the remote peer
|
/// \brief Send a formatted packet of data to the remote peer
|
||||||
///
|
///
|
||||||
|
/// In non-blocking mode, if this function returns sf::Socket::Partial,
|
||||||
|
/// you \em must retry sending the same unmodified packet before sending
|
||||||
|
/// anything else in order to guarantee the packet arrives at the remote
|
||||||
|
/// peer uncorrupted.
|
||||||
/// This function will fail if the socket is not connected.
|
/// This function will fail if the socket is not connected.
|
||||||
///
|
///
|
||||||
/// \param packet Packet to send
|
/// \param packet Packet to send
|
||||||
|
@ -37,6 +37,7 @@ namespace sf
|
|||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Packet::Packet() :
|
Packet::Packet() :
|
||||||
m_readPos(0),
|
m_readPos(0),
|
||||||
|
m_sendPos(0),
|
||||||
m_isValid(true)
|
m_isValid(true)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -218,6 +218,18 @@ void TcpSocket::disconnect()
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////
|
||||||
Socket::Status TcpSocket::send(const void* data, std::size_t size)
|
Socket::Status TcpSocket::send(const void* data, std::size_t size)
|
||||||
|
{
|
||||||
|
if (!isBlocking())
|
||||||
|
err() << "Warning: Partial sends might not be handled properly." << std::endl;
|
||||||
|
|
||||||
|
std::size_t sent;
|
||||||
|
|
||||||
|
return send(data, size, sent);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////
|
||||||
|
Socket::Status TcpSocket::send(const void* data, std::size_t size, std::size_t& sent)
|
||||||
{
|
{
|
||||||
// Check the parameters
|
// Check the parameters
|
||||||
if (!data || (size == 0))
|
if (!data || (size == 0))
|
||||||
@ -227,16 +239,22 @@ Socket::Status TcpSocket::send(const void* data, std::size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Loop until every byte has been sent
|
// Loop until every byte has been sent
|
||||||
int sent = 0;
|
int result = 0;
|
||||||
int sizeToSend = static_cast<int>(size);
|
for (sent = 0; sent < size; sent += result)
|
||||||
for (int length = 0; length < sizeToSend; length += sent)
|
|
||||||
{
|
{
|
||||||
// Send a chunk of data
|
// Send a chunk of data
|
||||||
sent = ::send(getHandle(), static_cast<const char*>(data) + length, sizeToSend - length, flags);
|
result = ::send(getHandle(), static_cast<const char*>(data) + sent, size - sent, flags);
|
||||||
|
|
||||||
// Check for errors
|
// Check for errors
|
||||||
if (sent < 0)
|
if (result < 0)
|
||||||
return priv::SocketImpl::getErrorStatus();
|
{
|
||||||
|
Status status = priv::SocketImpl::getErrorStatus();
|
||||||
|
|
||||||
|
if ((status == NotReady) && sent)
|
||||||
|
return Partial;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Done;
|
return Done;
|
||||||
@ -294,17 +312,30 @@ Socket::Status TcpSocket::send(Packet& packet)
|
|||||||
|
|
||||||
// First convert the packet size to network byte order
|
// First convert the packet size to network byte order
|
||||||
Uint32 packetSize = htonl(static_cast<Uint32>(size));
|
Uint32 packetSize = htonl(static_cast<Uint32>(size));
|
||||||
|
|
||||||
// Allocate memory for the data block to send
|
// Allocate memory for the data block to send
|
||||||
std::vector<char> blockToSend(sizeof(packetSize) + size);
|
std::vector<char> blockToSend(sizeof(packetSize) + size);
|
||||||
|
|
||||||
// Copy the packet size and data into the block to send
|
// Copy the packet size and data into the block to send
|
||||||
std::memcpy(&blockToSend[0], &packetSize, sizeof(packetSize));
|
std::memcpy(&blockToSend[0], &packetSize, sizeof(packetSize));
|
||||||
if (size > 0)
|
if (size > 0)
|
||||||
std::memcpy(&blockToSend[0] + sizeof(packetSize), data, size);
|
std::memcpy(&blockToSend[0] + sizeof(packetSize), data, size);
|
||||||
|
|
||||||
// Send the data block
|
// Send the data block
|
||||||
return send(&blockToSend[0], blockToSend.size());
|
std::size_t sent;
|
||||||
|
Status status = send(&blockToSend[0] + packet.m_sendPos, blockToSend.size() - packet.m_sendPos, sent);
|
||||||
|
|
||||||
|
// In the case of a partial send, record the location to resume from
|
||||||
|
if (status == Partial)
|
||||||
|
{
|
||||||
|
packet.m_sendPos += sent;
|
||||||
|
}
|
||||||
|
else if (status == Done)
|
||||||
|
{
|
||||||
|
packet.m_sendPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user