From 86d4347af8532ef85472e47c01d645fa5ad1b3b1 Mon Sep 17 00:00:00 2001 From: Florent Le Coz Date: Fri, 28 Feb 2014 01:14:38 +0100 Subject: Avoid unnecessary copies by recv()ing data directly into the expat buffer --- src/network/socket_handler.cpp | 26 +++++++++++++++++++++----- src/network/socket_handler.hpp | 20 +++++++++++++++++--- 2 files changed, 38 insertions(+), 8 deletions(-) (limited to 'src/network') diff --git a/src/network/socket_handler.cpp b/src/network/socket_handler.cpp index 6f7cc3f..eb427b8 100644 --- a/src/network/socket_handler.cpp +++ b/src/network/socket_handler.cpp @@ -138,11 +138,16 @@ void SocketHandler::set_poller(Poller* poller) this->poller = poller; } -void SocketHandler::on_recv(const size_t nb) +void SocketHandler::on_recv() { - char buf[4096]; + static constexpr size_t buf_size = 4096; + char buf[buf_size]; + void* recv_buf = this->get_receive_buffer(buf_size); - ssize_t size = ::recv(this->socket, buf, nb, 0); + if (recv_buf == nullptr) + recv_buf = buf; + + ssize_t size = ::recv(this->socket, recv_buf, buf_size, 0); if (0 == size) { this->on_connection_close(); @@ -156,8 +161,14 @@ void SocketHandler::on_recv(const size_t nb) } else { - this->in_buf += std::string(buf, size); - this->parse_in_buffer(); + if (buf == recv_buf) + { + // data needs to be placed in the in_buf string, because no buffer + // was provided to receive that data directly. The in_buf buffer + // will be handled in parse_in_buffer() + this->in_buf += std::string(buf, size); + } + this->parse_in_buffer(size); } } @@ -238,3 +249,8 @@ bool SocketHandler::is_connecting() const { return this->connecting; } + +void* SocketHandler::get_receive_buffer(const size_t) const +{ + return nullptr; +} diff --git a/src/network/socket_handler.hpp b/src/network/socket_handler.hpp index 8828596..35b0fdc 100644 --- a/src/network/socket_handler.hpp +++ b/src/network/socket_handler.hpp @@ -41,7 +41,7 @@ public: * Reads data in our in_buf and the call parse_in_buf, for the implementor * to handle the data received so far. */ - void on_recv(const size_t nb = 4096); + void on_recv(); /** * Write as much data from out_buf as possible, in the socket. */ @@ -73,14 +73,28 @@ public: */ virtual void on_connection_close() = 0; /** - * Handle/consume (some of) the data received so far. If some data is used, the in_buf + * Handle/consume (some of) the data received so far. The data to handle + * may be in the in_buf buffer, or somewhere else, depending on what + * get_receive_buffer() returned. If some data is used from in_buf, it * should be truncated, only the unused data should be left untouched. + * + * The size argument is the size of the last chunk of data that was added to the buffer. */ - virtual void parse_in_buffer() = 0; + virtual void parse_in_buffer(const size_t size) = 0; bool is_connected() const; bool is_connecting() const; protected: + /** + * Provide a buffer in which data can be directly received. This can be + * used to avoid copying data into in_buf before using it. If no buffer + * can provided, nullptr is returned (the default implementation does + * that). + */ + virtual void* get_receive_buffer(const size_t size) const; + /** + * The handled socket. + */ socket_t socket; /** * Where data read from the socket is added until we can extract a full -- cgit v1.2.3