muduo 프로그래밍 예제의 5가지 간단한 TCP 예제

머리말

5개의 간단한 TCP 예제는 폐기, 주간, 시간, 에코 및 요금이며 이러한 기능은 다음과 같이 설명됩니다
.
daytime: 서버가 연결을 수락한 후 현재 시간을 문자열 형태로 보낸 다음 능동적으로 연결을 끊습니다.
time: 서버가 연결을 수락한 후 현재 시간을 바이너리 형식으로 전송한 다음 능동적으로 연결을 끊습니다. 수신된 시간을 문자열로 변환하는 클라이언트 프로그램이 필요합니다.
echo: 에코 서비스, 수신된 데이터를 다시 클라이언트로 보냅니다.
Chargen: 서버가 연결을 수락한 후 테스트 데이터를 계속 전송합니다.

<<UNIX Network Programming Volume 1>>에 언급되어 있으며 Chapter 2 2.12 Standard Internet Services를 참조하십시오.
여기에 이미지 설명 삽입


5개의 간단한 TCP

1. 버리다

비교적 간단하며 "3.5 이벤트"에서 "메시지/데이터 도착" 이벤트만 신경쓰며 이벤트 처리 기능은 다음과 같습니다.

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();
}

달리다:

服务端:
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은 짧은 연결 프로토콜로, 현재 시간을 보낸 후 서버가 능동적으로 연결을 끊습니다. "3.5 이벤트"에서 "연결 설정" 이벤트에만 주의하면 되며 이벤트 처리 기능은 다음과 같습니다.

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();
  }
}

달리다:

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. 에코

버리기보다 하나 더 추가conn->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. 시간

시간 프로토콜은 datetime 문자열 대신 1970-01-01 00:00:00Z부터 현재까지의 초 수를 나타내는 32비트 정수를 반환한다는 점을 제외하면 daytime과 유사합니다. 물론 이 합의에는 '2038 문제'가 있다. 서버는
"three and a half events"의 "연결 설정" 이벤트와 이벤트 처리 기능에만 주의를 기울이면 됩니다.

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();
  }
}

고객:

#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. 배치

이 프로토콜은 다소 특별하여 데이터를 전송만 하고 수신은 하지 않습니다. 또한 보내는 데이터는 클라이언트가 받을 수 있는 것보다 빠를 수 없으므로 "메시지/데이터 전송" 이벤트(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;
}


추천

출처blog.csdn.net/nc_linux/article/details/125025985