summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2014-02-27 23:43:05 +0100
committerFlorent Le Coz <louiz@louiz.org>2014-02-27 23:43:05 +0100
commitdf774d45a9754274a1701d801e4a42e71d38c97c (patch)
tree862200bfd6154a9f3c4b88aefeb6e6ba27f1a078
parente2b9e80244abe0712b8d7e3a8f9e3a3474072a4b (diff)
downloadbiboumi-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.cpp49
-rw-r--r--src/network/socket_handler.hpp5
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