diff options
author | Florent Le Coz <louiz@louiz.org> | 2014-02-27 23:43:05 +0100 |
---|---|---|
committer | Florent Le Coz <louiz@louiz.org> | 2014-02-27 23:43:05 +0100 |
commit | df774d45a9754274a1701d801e4a42e71d38c97c (patch) | |
tree | 862200bfd6154a9f3c4b88aefeb6e6ba27f1a078 | |
parent | e2b9e80244abe0712b8d7e3a8f9e3a3474072a4b (diff) | |
download | biboumi-df774d45a9754274a1701d801e4a42e71d38c97c.tar.gz biboumi-df774d45a9754274a1701d801e4a42e71d38c97c.tar.bz2 biboumi-df774d45a9754274a1701d801e4a42e71d38c97c.tar.xz biboumi-df774d45a9754274a1701d801e4a42e71d38c97c.zip |
Use scatter/gather io with sendmsg to avoid concataning strings all the time
-rw-r--r-- | src/network/socket_handler.cpp | 49 | ||||
-rw-r--r-- | src/network/socket_handler.hpp | 5 |
2 files changed, 43 insertions, 11 deletions
diff --git a/src/network/socket_handler.cpp b/src/network/socket_handler.cpp index ca9d9e2..6f7cc3f 100644 --- a/src/network/socket_handler.cpp +++ b/src/network/socket_handler.cpp @@ -17,6 +17,10 @@ #include <iostream> +#ifndef UIO_FASTIOV +# define UIO_FASTIOV 8 +#endif + SocketHandler::SocketHandler(): poller(nullptr), connected(false), @@ -159,16 +163,44 @@ void SocketHandler::on_recv(const size_t nb) void SocketHandler::on_send() { - const ssize_t res = ::send(this->socket, this->out_buf.data(), this->out_buf.size(), MSG_NOSIGNAL); - if (res == -1) + struct iovec msg_iov[UIO_FASTIOV] = {}; + struct msghdr msg{nullptr, 0, + msg_iov, + 0, nullptr, 0, 0}; + for (std::string& s: this->out_buf) + { + // unconsting the content of s is ok, sendmsg will never modify it + msg_iov[msg.msg_iovlen].iov_base = const_cast<char*>(s.data()); + msg_iov[msg.msg_iovlen].iov_len = s.size(); + msg.msg_iovlen++; + } + ssize_t res = ::sendmsg(this->socket, &msg, MSG_NOSIGNAL); + if (res < 0) { - log_error("send failed: " << strerror(errno)); + log_error("sendmsg failed: " << strerror(errno)); this->on_connection_close(); this->close(); } else { - this->out_buf = this->out_buf.substr(res, std::string::npos); + // remove all the strings that were successfully sent. + for (auto it = this->out_buf.begin(); + it != this->out_buf.end();) + { + if (static_cast<size_t>(res) >= (*it).size()) + { + res -= (*it).size(); + it = this->out_buf.erase(it); + } + else + { + // If one string has partially been sent, we use substr to + // crop it + if (res > 0) + (*it) = (*it).substr(res, std::string::npos); + break; + } + } if (this->out_buf.empty()) this->poller->stop_watching_send_events(this); } @@ -191,11 +223,10 @@ socket_t SocketHandler::get_socket() const void SocketHandler::send_data(std::string&& data) { - this->out_buf += std::move(data); - if (!this->out_buf.empty()) - { - this->poller->watch_send_events(this); - } + if (data.empty()) + return ; + this->out_buf.emplace_back(std::move(data)); + this->poller->watch_send_events(this); } bool SocketHandler::is_connected() const diff --git a/src/network/socket_handler.hpp b/src/network/socket_handler.hpp index fcc8734..8828596 100644 --- a/src/network/socket_handler.hpp +++ b/src/network/socket_handler.hpp @@ -5,8 +5,9 @@ #include <sys/socket.h> #include <netdb.h> -#include <string> #include <utility> +#include <string> +#include <list> typedef int socket_t; @@ -91,7 +92,7 @@ protected: /** * Where data is added, when we want to send something to the client. */ - std::string out_buf; + std::list<std::string> out_buf; /** * A pointer to the poller that manages us, because we need to communicate * with it, sometimes (for example to tell it that he now needs to watch |