~singpolyma/biboumi

df774d45a9754274a1701d801e4a42e71d38c97c — Florent Le Coz 10 years ago e2b9e80
Use scatter/gather io with sendmsg to avoid concataning strings all the time
2 files changed, 43 insertions(+), 11 deletions(-)

M src/network/socket_handler.cpp
M src/network/socket_handler.hpp
M src/network/socket_handler.cpp => src/network/socket_handler.cpp +40 -9
@@ 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

M src/network/socket_handler.hpp => src/network/socket_handler.hpp +3 -2
@@ 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