Network/TcpClient|UdpSocket: Add SendMultiple method

To efficiently merge multiples buffers into a reduced number of network
packets
This commit is contained in:
Lynix 2017-01-27 14:51:01 +01:00
parent 1d6f22cd8a
commit ab3b730d21
10 changed files with 201 additions and 11 deletions

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Jérôme Leclercq
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@ -68,4 +68,4 @@ namespace Nz
#include <Nazara/Network/AbstractSocket.inl>
#endif // NAZARA_ABSTRACTSOCKET_HPP
#endif // NAZARA_ABSTRACTSOCKET_HPP

View File

@ -0,0 +1,21 @@
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp
#pragma once
#ifndef NAZARA_NETBUFFER_HPP
#define NAZARA_NETBUFFER_HPP
#include <Nazara/Prerequesites.hpp>
namespace Nz
{
struct NetBuffer
{
void* data;
std::size_t dataLength;
};
}
#endif // NAZARA_NETBUFFER_HPP

View File

@ -13,6 +13,7 @@
#include <Nazara/Core/Stream.hpp>
#include <Nazara/Network/AbstractSocket.hpp>
#include <Nazara/Network/IpAddress.hpp>
#include <Nazara/Network/NetBuffer.hpp>
namespace Nz
{
@ -49,6 +50,7 @@ namespace Nz
bool ReceivePacket(NetPacket* packet);
bool Send(const void* buffer, std::size_t size, std::size_t* sent);
bool SendMultiple(const NetBuffer* buffers, std::size_t bufferCount, std::size_t* sent);
bool SendPacket(const NetPacket& packet);
bool SetCursorPos(UInt64 offset) override;

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Jérôme Leclercq
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@ -10,6 +10,7 @@
#include <Nazara/Prerequesites.hpp>
#include <Nazara/Network/AbstractSocket.hpp>
#include <Nazara/Network/IpAddress.hpp>
#include <Nazara/Network/NetBuffer.hpp>
namespace Nz
{
@ -29,7 +30,7 @@ namespace Nz
inline bool Create(NetProtocol protocol);
void EnableBroadcasting(bool broadcasting);
inline IpAddress GetBoundAddress() const;
inline UInt16 GetBoundPort() const;
inline SocketState GetState() const;
@ -42,6 +43,7 @@ namespace Nz
bool ReceivePacket(NetPacket* packet, IpAddress* from);
bool Send(const IpAddress& to, const void* buffer, std::size_t size, std::size_t* sent);
bool SendMultiple(const IpAddress& to, const NetBuffer* buffers, std::size_t bufferCount, std::size_t* sent);
bool SendPacket(const IpAddress& to, const NetPacket& packet);
private:
@ -55,4 +57,4 @@ namespace Nz
#include <Nazara/Network/UdpSocket.inl>
#endif // NAZARA_UDPSOCKET_HPP
#endif // NAZARA_UDPSOCKET_HPP

View File

@ -577,6 +577,57 @@ namespace Nz
return true;
}
bool SocketImpl::SendMultiple(SocketHandle handle, const NetBuffer* buffers, std::size_t bufferCount, const IpAddress& to, int* sent, SocketError* error)
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");
NazaraAssert(buffers && bufferCount > 0, "Invalid buffers");
StackAllocation memory = NazaraStackAllocation(bufferCount * sizeof(iovec));
iovec* sysBuffers = static_cast<iovec*>(memory.GetPtr());
for (std::size_t i = 0; i < bufferCount; ++i)
{
sysBuffers[i].iov_base = buffers[i].data;
sysBuffers[i].iov_len = buffers[i].dataLength;
}
struct msghdr header;
std::memset(&header, 0, sizeof(header);
IpAddressImpl::SockAddrBuffer nameBuffer;
header.msg_namelen = IpAddressImpl::ToSockAddr(to, nameBuffer.data());
header.msg_name = nameBuffer.data();
msgHdr.msg_iov = sysBuffers;
msgHdr.msg_iovlen = static_cast<int>(bufferCount);
int sentLength = sendmsg (socket, &msgHdr, MSG_NOSIGNAL);
if (byteSent == SOCKET_ERROR)
{
int errorCode = GetLastErrorCode();
switch (errorCode)
{
case EWOULDBLOCK:
byteSent = 0;
break;
default:
{
if (error)
*error = TranslateErrnoToResolveError(errorCode);
return false; //< Error
}
}
}
if (sent)
*sent = static_cast<int>(byteSent);
if (error)
*error = SocketError_NoError;
return true;
}
bool SocketImpl::SendTo(SocketHandle handle, const void* buffer, int length, const IpAddress& to, int* sent, SocketError* error)
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");

View File

@ -64,6 +64,7 @@ namespace Nz
static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error);
static bool Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error);
static bool SendMultiple(SocketHandle handle, const NetBuffer* buffers, std::size_t bufferCount, const IpAddress& to, int* sent, SocketError* error);
static bool SendTo(SocketHandle handle, const void* buffer, int length, const IpAddress& to, int* sent, SocketError* error);
static bool SetBlocking(SocketHandle handle, bool blocking, SocketError* error = nullptr);

View File

@ -353,6 +353,45 @@ namespace Nz
return true;
}
/*!
* \brief Sends multiple buffers at once
* \return true If data were sent
*
* \param buffers A pointer to an array of NetBuffer containing buffers and size data
* \param size Number of NetBuffer to send
* \param sent Optional argument to get the number of bytes sent
*/
bool TcpClient::SendMultiple(const NetBuffer* buffers, std::size_t bufferCount, std::size_t* sent)
{
NazaraAssert(buffers && bufferCount > 0, "Invalid buffer");
int byteSent;
if (!SocketImpl::SendMultiple(m_handle, buffers, bufferCount, m_peerAddress, &byteSent, &m_lastError))
{
switch (m_lastError)
{
case SocketError_ConnectionClosed:
case SocketError_ConnectionRefused:
UpdateState(SocketState_NotConnected);
break;
default:
break;
}
if (sent)
*sent = byteSent;
return false;
}
if (sent)
*sent = byteSent;
UpdateState(SocketState_Connected);
return true;
}
/*!
* \brief Sends the packet available
* \return true If packet sent

View File

@ -179,6 +179,31 @@ namespace Nz
return true;
}
/*!
* \brief Sends multiple buffers as one datagram
* \return true If data were sent
*
* \param to Destination IpAddress (must match socket protocol)
* \param buffers A pointer to an array of NetBuffer containing buffers and size data
* \param size Number of NetBuffer to send
* \param sent Optional argument to get the number of bytes sent
*/
bool UdpSocket::SendMultiple(const IpAddress& to, const NetBuffer* buffers, std::size_t bufferCount, std::size_t* sent)
{
NazaraAssert(to.IsValid(), "Invalid ip address");
NazaraAssert(to.GetProtocol() == m_protocol, "IP Address has a different protocol than the socket");
NazaraAssert(buffers && bufferCount > 0, "Invalid buffer");
int byteSent;
if (!SocketImpl::SendMultiple(m_handle, buffers, bufferCount, to, &byteSent, &m_lastError))
return false;
if (sent)
*sent = byteSent;
return true;
}
/*!
* \brief Sends the packet available
* \return true If packet sent

View File

@ -608,6 +608,53 @@ namespace Nz
return true;
}
bool SocketImpl::SendMultiple(SocketHandle handle, const NetBuffer* buffers, std::size_t bufferCount, const IpAddress& to, int* sent, SocketError* error)
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");
NazaraAssert(buffers && bufferCount > 0, "Invalid buffers");
IpAddressImpl::SockAddrBuffer nameBuffer;
int bufferLength = IpAddressImpl::ToSockAddr(to, nameBuffer.data());
StackAllocation memory = NazaraStackAllocation(bufferCount * sizeof(WSABUF));
WSABUF* winBuffers = static_cast<WSABUF*>(memory.GetPtr());
for (std::size_t i = 0; i < bufferCount; ++i)
{
winBuffers[i].buf = static_cast<CHAR*>(buffers[i].data);
winBuffers[i].len = static_cast<ULONG>(buffers[i].dataLength);
}
DWORD byteSent;
if (WSASendTo(handle, winBuffers, static_cast<DWORD>(bufferCount), &byteSent, 0, reinterpret_cast<const sockaddr*>(nameBuffer.data()), bufferLength, nullptr, nullptr) == SOCKET_ERROR)
{
int errorCode = WSAGetLastError();
switch (errorCode)
{
case WSAEWOULDBLOCK:
{
byteSent = 0;
break;
}
default:
{
if (error)
*error = TranslateWSAErrorToSocketError(errorCode);
return false; //< Error
}
}
}
if (sent)
*sent = static_cast<int>(byteSent);
if (error)
*error = SocketError_NoError;
return true;
}
bool SocketImpl::SendTo(SocketHandle handle, const void* buffer, int length, const IpAddress& to, int* sent, SocketError* error)
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");
@ -719,7 +766,7 @@ namespace Nz
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");
DWORD option = size;
DWORD option = static_cast<DWORD>(size);
if (setsockopt(handle, SOL_SOCKET, SO_RCVBUF, reinterpret_cast<const char*>(&option), sizeof(option)) == SOCKET_ERROR)
{
if (error)
@ -738,7 +785,7 @@ namespace Nz
{
NazaraAssert(handle != InvalidHandle, "Invalid handle");
DWORD option = size;
DWORD option = static_cast<DWORD>(size);
if (setsockopt(handle, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char*>(&option), sizeof(option)) == SOCKET_ERROR)
{
if (error)

View File

@ -1,4 +1,4 @@
// Copyright (C) 2017 Jérôme Leclercq
// Copyright (C) 2017 Jérôme Leclercq
// This file is part of the "Nazara Engine - Network module"
// For conditions of distribution and use, see copyright notice in Config.hpp
@ -7,9 +7,10 @@
#ifndef NAZARA_SOCKETIMPL_HPP
#define NAZARA_SOCKETIMPL_HPP
#include <Nazara/Network/SocketHandle.hpp>
#include <Nazara/Network/Enums.hpp>
#include <Nazara/Network/IpAddress.hpp>
#include <Nazara/Network/NetBuffer.hpp>
#include <Nazara/Network/SocketHandle.hpp>
#include <winsock2.h>
#define NAZARA_NETWORK_POLL_SUPPORT NAZARA_CORE_WINDOWS_NT6
@ -34,7 +35,7 @@ namespace Nz
static SocketState Bind(SocketHandle handle, const IpAddress& address, SocketError* error);
static SocketHandle Create(NetProtocol protocol, SocketType type, SocketError* error);
static void ClearErrorCode(SocketHandle handle);
static void Close(SocketHandle handle);
@ -65,6 +66,7 @@ namespace Nz
static bool ReceiveFrom(SocketHandle handle, void* buffer, int length, IpAddress* from, int* read, SocketError* error);
static bool Send(SocketHandle handle, const void* buffer, int length, int* sent, SocketError* error);
static bool SendMultiple(SocketHandle handle, const NetBuffer* buffers, std::size_t bufferCount, const IpAddress& to, int* sent, SocketError* error);
static bool SendTo(SocketHandle handle, const void* buffer, int length, const IpAddress& to, int* sent, SocketError* error);
static bool SetBlocking(SocketHandle handle, bool blocking, SocketError* error = nullptr);
@ -87,4 +89,4 @@ namespace Nz
};
}
#endif // NAZARA_SOCKETIMPL_HPP
#endif // NAZARA_SOCKETIMPL_HPP