Five simple TCP examples of muduo programming examples

foreword

Five simple TCP examples are discard, daytime, time, echo, and chargen. These functions are described as follows:
discard: discard all received data.
daytime: After the server accepts the connection, it sends the current time in the form of a string, and then actively disconnects.
time: After the server accepts the connection, it sends the current time in binary form, and then actively disconnects. We need a client program to convert the received time into a string.
echo: Echo service, send the received data back to the client.
Chargen: After the server accepts the connection, it keeps sending test data.

It is mentioned in <<UNIX Network Programming Volume 1>>, refer to Chapter 2 2.12 Standard Internet Services
insert image description here


Five Simple TCPs

1. discard

It is relatively simple, and only cares about the "message/data arrival" event in the "three and a half events". The event processing function is as follows:

void DiscardServer::onMessage(const TcpConnectionPtr& conn,
                              Buffer* buf,
                              Timestamp time)
{
  string msg(buf->retrieveAllAsString());
  LOG_INFO << conn->name() << " discards " << msg.size()
           << " bytes received at " << time.toString();
}

run:

服务端:
root@ubuntu:/opt/muduo/examples/simple/discard# ./a.out 
20220528 17:05:13.611973Z 62510 INFO  pid = 62510 - main.cc:13
20220528 17:05:22.777054Z 62510 INFO  TcpServer::newConnection [DiscardServer] - new connection [DiscardServer-0.0.0.0:2009#1] from 192.168.1.14:57380 - TcpServer.cc:80
20220528 17:05:22.777182Z 62510 INFO  DiscardServer - 192.168.1.14:57380 -> 192.168.1.14:2009 is UP - discard.cc:25
20220528 17:05:25.590716Z 62510 INFO  DiscardServer-0.0.0.0:2009#1 discards 1 bytes received at 1653757525.590698 - discard.cc:35
20220528 17:05:25.798819Z 62510 INFO  DiscardServer-0.0.0.0:2009#1 discards 1 bytes received at 1653757525.798808 - discard.cc:35
20220528 17:05:26.020168Z 62510 INFO  DiscardServer-0.0.0.0:2009#1 discards 1 bytes received at 1653757526.020155 - discard.cc:35
20220528 17:05:26.234700Z 62510 INFO  DiscardServer-0.0.0.0:2009#1 discards 1 bytes received at 1653757526.234687 - discard.cc:35
20220528 17:05:26.425043Z 62510 INFO  DiscardServer-0.0.0.0:2009#1 discards 1 bytes received at 1653757526.425030 - discard.cc:35
20220528 17:05:30.313801Z 62510 INFO  DiscardServer-0.0.0.0:2009#1 discards 4 bytes received at 1653757530.313788 - discard.cc:35

客户端使用netcat的nc命令模拟:
root@ubuntu:/home/lvch# nc 192.168.1.14 2009




123

2.daytime

daytime is a short connection protocol, after sending the current time, the server actively disconnects the connection. It only needs to pay attention to the "connection established" event in the "three and a half events", and the event processing function is as follows:

void DaytimeServer::onConnection(const TcpConnectionPtr& conn)
{
  LOG_INFO << "DaytimeServer - " << conn->peerAddress().toIpPort() << " -> "
           << conn->localAddress().toIpPort() << " is "
           << (conn->connected() ? "UP" : "DOWN");
  if (conn->connected())
  {
    conn->send(Timestamp::now().toFormattedString() + "\n");
    conn->shutdown();
  }
}

run:

root@ubuntu:/opt/muduo/examples/simple/daytime# ./a.out 
20220528 17:10:57.295966Z 62523 INFO  pid = 62523 - main.cc:13
20220528 17:11:04.130141Z 62523 INFO  TcpServer::newConnection [DaytimeServer] - new connection [DaytimeServer-0.0.0.0:2013#1] from 192.168.1.14:49562 - TcpServer.cc:80
20220528 17:11:04.130248Z 62523 INFO  DaytimeServer - 192.168.1.14:49562 -> 192.168.1.14:2013 is UP - daytime.cc:26

`客户端:
root@ubuntu:/home/lvch# nc 192.168.1.14 2013
20220528 17:11:04.130295

3. echo

Add one more than discardconn->send(msg);

void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn,
                           muduo::net::Buffer* buf,
                           muduo::Timestamp time)
{
  muduo::string msg(buf->retrieveAllAsString());
  LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, "
           << "data received at " << time.toString();
  conn->send(msg);
}

4. time

The time protocol is similar to daytime, except that instead of a datetime string, it returns a 32-bit integer representing the number of seconds from 1970-01-01 00:00:00Z to the present. Of course this agreement has the "2038 problem". The server only needs to pay attention to
the "connection established" event in the "three and a half events", and the event processing function:

void TimeServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
{
  LOG_INFO << "TimeServer - " << conn->peerAddress().toIpPort() << " -> "
           << conn->localAddress().toIpPort() << " is "
           << (conn->connected() ? "UP" : "DOWN");
  if (conn->connected())
  {
    time_t now = ::time(NULL);
    int32_t be32 = sockets::hostToNetwork32(static_cast<int32_t>(now));
    conn->send(&be32, sizeof be32);
    conn->shutdown();
  }
}

client:

#include "muduo/base/Logging.h"
#include "muduo/net/Endian.h"
#include "muduo/net/EventLoop.h"
#include "muduo/net/InetAddress.h"
#include "muduo/net/TcpClient.h"

#include <utility>

#include <stdio.h>
#include <unistd.h>

using namespace muduo;
using namespace muduo::net;

class TimeClient : noncopyable
{
 public:
  TimeClient(EventLoop* loop, const InetAddress& serverAddr)
    : loop_(loop),
      client_(loop, serverAddr, "TimeClient")
  {
    client_.setConnectionCallback(
        std::bind(&TimeClient::onConnection, this, _1));
    client_.setMessageCallback(
        std::bind(&TimeClient::onMessage, this, _1, _2, _3));
    // client_.enableRetry();
  }

  void connect()
  {
    client_.connect();
  }

 private:

  EventLoop* loop_;
  TcpClient client_;

  void onConnection(const TcpConnectionPtr& conn)
  {
    LOG_INFO << conn->localAddress().toIpPort() << " -> "
             << conn->peerAddress().toIpPort() << " is "
             << (conn->connected() ? "UP" : "DOWN");

    if (!conn->connected())
    {
      loop_->quit();
    }
  }

  void onMessage(const TcpConnectionPtr& conn, Buffer* buf, Timestamp receiveTime)
  {
    if (buf->readableBytes() >= sizeof(int32_t))
    {
      const void* data = buf->peek();
      int32_t be32 = *static_cast<const int32_t*>(data);
      buf->retrieve(sizeof(int32_t));
      time_t time = sockets::networkToHost32(be32);
      Timestamp ts(implicit_cast<uint64_t>(time) * Timestamp::kMicroSecondsPerSecond);
      LOG_INFO << "Server time = " << time << ", " << ts.toFormattedString();
    }
    else
    {
      LOG_INFO << conn->name() << " no enough data " << buf->readableBytes()
               << " at " << receiveTime.toFormattedString();
    }
  }
};

int main(int argc, char* argv[])
{
  LOG_INFO << "pid = " << getpid();
  if (argc > 1)
  {
    EventLoop loop;
    InetAddress serverAddr(argv[1], 2037);

    TimeClient timeClient(&loop, serverAddr);
    timeClient.connect();
    loop.loop();
  }
  else
  {
    printf("Usage: %s host_ip\n", argv[0]);
  }
}


5. batches

The protocol is rather special, only sending but not receiving data. Moreover, the data it sends cannot be faster than the client can receive it, so you need to pay attention to the "message/data sent" event (onWriteComplete)

`#include "examples/simple/chargen/chargen.h"

#include "muduo/base/Logging.h"
#include "muduo/net/EventLoop.h"

#include <stdio.h>

using namespace muduo;
using namespace muduo::net;

ChargenServer::ChargenServer(EventLoop* loop,
                             const InetAddress& listenAddr,
                             bool print)
  : server_(loop, listenAddr, "ChargenServer"),
    transferred_(0),
    startTime_(Timestamp::now())
{
  server_.setConnectionCallback(
      std::bind(&ChargenServer::onConnection, this, _1));
  server_.setMessageCallback(
      std::bind(&ChargenServer::onMessage, this, _1, _2, _3));
  server_.setWriteCompleteCallback(
      std::bind(&ChargenServer::onWriteComplete, this, _1));
  if (print)
  {
    loop->runEvery(3.0, std::bind(&ChargenServer::printThroughput, this));
  }

  string line;
  for (int i = 33; i < 127; ++i)
  {
    line.push_back(char(i));
  }
  line += line;

  for (size_t i = 0; i < 127-33; ++i)
  {
    message_ += line.substr(i, 72) + '\n';
  }
}

void ChargenServer::start()
{
  server_.start();
}

void ChargenServer::onConnection(const TcpConnectionPtr& conn)
{
  LOG_INFO << "ChargenServer - " << conn->peerAddress().toIpPort() << " -> "
           << conn->localAddress().toIpPort() << " is "
           << (conn->connected() ? "UP" : "DOWN");
  if (conn->connected())
  {
    conn->setTcpNoDelay(true);
    conn->send(message_);
  }
}

void ChargenServer::onMessage(const TcpConnectionPtr& conn,
                              Buffer* buf,
                              Timestamp time)
{
  string msg(buf->retrieveAllAsString());
  LOG_INFO << conn->name() << " discards " << msg.size()
           << " bytes received at " << time.toString();
}

void ChargenServer::onWriteComplete(const TcpConnectionPtr& conn)
{
  transferred_ += message_.size();
  conn->send(message_);
}

void ChargenServer::printThroughput()
{
  Timestamp endTime = Timestamp::now();
  double time = timeDifference(endTime, startTime_);
  printf("%4.3f MiB/s\n", static_cast<double>(transferred_)/time/1024/1024);
  transferred_ = 0;
  startTime_ = endTime;
}


Guess you like

Origin blog.csdn.net/nc_linux/article/details/125025985