Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use sendfile on Linux to optimize memory and improve latency #3277 #3368

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Net/include/Poco/Net/SocketImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,16 @@ class Net_API SocketImpl: public Poco::RefCountedObject
///
/// Always returns zero for platforms where not implemented.

virtual void sendFile(const std::string& filePath, const size_t fileSize);
/// Implemented only on Linux. Noop on other platforms.
///
/// Sends the given file via sendfile system call.
/// Blocks the calling thread until the file is sent or the connection
/// is closed by the client.
///
/// @param filePath [i] path of the file on file system.
/// @param fileSize [i] size of the file being sent.

virtual int receiveBytes(void* buffer, int length, int flags = 0);
/// Receives data from the socket and stores it
/// in buffer. Up to length bytes are received.
Expand Down
3 changes: 3 additions & 0 deletions Net/include/Poco/Net/StreamSocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,9 @@ class Net_API StreamSocket: public Socket
/// The flags parameter can be used to pass system-defined flags
/// for send() like MSG_OOB.

virtual void sendFile(const std::string& filePath, const size_t fileSize);
/// Sends the given file to the socket

int receiveBytes(void* buffer, int length, int flags = 0);
/// Receives data from the socket and stores it
/// in buffer. Up to length bytes are received.
Expand Down
12 changes: 10 additions & 2 deletions Net/src/HTTPServerResponseImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
// SPDX-License-Identifier: BSL-1.0
//


#include "Poco/Net/HTTPServerResponseImpl.h"
#include "Poco/Net/HTTPServerRequestImpl.h"
#include "Poco/Net/HTTPServerSession.h"
Expand Down Expand Up @@ -53,7 +52,8 @@ HTTPServerResponseImpl::HTTPServerResponseImpl(HTTPServerSession& session):

HTTPServerResponseImpl::~HTTPServerResponseImpl()
{
delete _pStream;
if (_pStream != 0)
delete _pStream;
}


Expand Down Expand Up @@ -128,7 +128,15 @@ void HTTPServerResponseImpl::sendFile(const std::string& path, const std::string
write(*_pStream);
if (_pRequest && _pRequest->getMethod() != HTTPRequest::HTTP_HEAD)
{
#if (POCO_OS == POCO_OS_LINUX)
// delete the stream to flush the HTTP headers to the socket, required by HTTP 1.0 and above
delete _pStream;
_pStream = 0;
// send the file via socket handle
_session.socket().sendFile(path, length);
#else
StreamCopier::copyStream(istr, *_pStream);
#endif
}
}
else throw OpenFileException(path);
Expand Down
28 changes: 28 additions & 0 deletions Net/src/SocketImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,14 @@
//


#ifdef __linux__
#include <fcntl.h>
#include <sys/sendfile.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <iostream>
#endif

#include "Poco/Net/SocketImpl.h"
#include "Poco/Net/NetException.h"
#include "Poco/Net/StreamSocketImpl.h"
Expand Down Expand Up @@ -370,6 +378,26 @@ int SocketImpl::sendBytes(const SocketBufVec& buffers, int flags)
}


void SocketImpl::sendFile(const std::string& filePath, const size_t fileSize)
{
#if (POCO_OS == POCO_OS_LINUX)
int filefd = ::open(filePath.data(), O_RDONLY);
size_t remaining = fileSize;
while (remaining > 0)
{
ssize_t sent = ::sendfile64(_sockfd, filefd, 0, remaining);
if (sent >= 0)
remaining -= sent;
else
break;
}
// instruct the kernel to drop the file cache
::posix_fadvise(filefd, 0, 0, POSIX_FADV_DONTNEED);
::close(filefd);
#endif
}


int SocketImpl::receiveBytes(void* buffer, int length, int flags)
{
checkBrokenTimeout(SELECT_READ);
Expand Down
6 changes: 6 additions & 0 deletions Net/src/StreamSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,12 @@ int StreamSocket::sendBytes(FIFOBuffer& fifoBuf)
}


void StreamSocket::sendFile(const std::string& filePath, const size_t fileSize)
{
impl()->sendFile(filePath, fileSize);
}


int StreamSocket::receiveBytes(void* buffer, int length, int flags)
{
return impl()->receiveBytes(buffer, length, flags);
Expand Down