1.五个简单TCP协议

1)discard--丢弃所有收到的数据

#include "discard.h"
#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
using namespace muduo;
using namespace muduo::net;
int main()
{
  LOG_INFO << "pid = " << getpid();
  EventLoop loop;
  InetAddress listenAddr(2009);
  DiscardServer server(&loop, listenAddr);
  server.start();
  loop.loop();
}

最简单的默认调用方式,所有server开头都这么写

#ifndef MUDUO_EXAMPLES_SIMPLE_DISCARD_DISCARD_H
#define MUDUO_EXAMPLES_SIMPLE_DISCARD_DISCARD_H
#include <muduo/net/TcpServer.h>
// RFC 863
class DiscardServer
{
 public:
  DiscardServer(muduo::net::EventLoop* loop,
                const muduo::net::InetAddress& listenAddr);
  void start();
 private:
  void onConnection(const muduo::net::TcpConnectionPtr& conn);
  void onMessage(const muduo::net::TcpConnectionPtr& conn,
                 muduo::net::Buffer* buf,
                 muduo::Timestamp time);
  muduo::net::EventLoop* loop_;
  muduo::net::TcpServer server_;
};
#endif  // MUDUO_EXAMPLES_SIMPLE_DISCARD_DISCARD_H

也是基本的写法,用到了onConnection和onMessage回调函数,当然还有其他的回调接口,日后再说

#include "discard.h"
#include <muduo/base/Logging.h>
#include <boost/bind.hpp>
using namespace muduo;
using namespace muduo::net;
DiscardServer::DiscardServer(EventLoop* loop,
                             const InetAddress& listenAddr)
  : loop_(loop),
    server_(loop, listenAddr, "DiscardServer")
{
  server_.setConnectionCallback(
      boost::bind(&DiscardServer::onConnection, this, _1));
  server_.setMessageCallback(
      boost::bind(&DiscardServer::onMessage, this, _1, _2, _3));
}
void DiscardServer::start()
{
  server_.start();
}
void DiscardServer::onConnection(const TcpConnectionPtr& conn)
{
  LOG_INFO << "DiscardServer - " << conn->peerAddress().toIpPort() << " -> "
           << conn->localAddress().toIpPort() << " is "
           << (conn->connected() ? "UP" : "DOWN");
}
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();
}

丢弃就是onMessage里面对接收到的buffer不处理。


2)daytime服务

#include "daytime.h"
#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
using namespace muduo;
using namespace muduo::net;
int main()
{
  LOG_INFO << "pid = " << getpid();
  EventLoop loop;
  InetAddress listenAddr(2013);
  DaytimeServer server(&loop, listenAddr);
  server.start();
  loop.loop();
}
#ifndef MUDUO_EXAMPLES_SIMPLE_DAYTIME_DAYTIME_H
#define MUDUO_EXAMPLES_SIMPLE_DAYTIME_DAYTIME_H
#include <muduo/net/TcpServer.h>
// RFC 867
class DaytimeServer
{
 public:
  DaytimeServer(muduo::net::EventLoop* loop,
                const muduo::net::InetAddress& listenAddr);
  void start();
 private:
  void onConnection(const muduo::net::TcpConnectionPtr& conn);
  void onMessage(const muduo::net::TcpConnectionPtr& conn,
                 muduo::net::Buffer* buf,
                 muduo::Timestamp time);
  muduo::net::EventLoop* loop_;
  muduo::net::TcpServer server_;
};
#endif  // MUDUO_EXAMPLES_SIMPLE_DAYTIME_DAYTIME_H

以上两个文件,和discard服务一样

#include "daytime.h"
#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
#include <boost/bind.hpp>
using namespace muduo;
using namespace muduo::net;
DaytimeServer::DaytimeServer(EventLoop* loop,
                             const InetAddress& listenAddr)
  : loop_(loop),
    server_(loop, listenAddr, "DaytimeServer")
{
  server_.setConnectionCallback(
      boost::bind(&DaytimeServer::onConnection, this, _1));
  server_.setMessageCallback(
      boost::bind(&DaytimeServer::onMessage, this, _1, _2, _3));
}
void DaytimeServer::start()
{
  server_.start();
}
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();
  }
}
void DaytimeServer::onMessage(const TcpConnectionPtr& conn,
                              Buffer* buf,
                              Timestamp time)
{
  string msg(buf->retrieveAllAsString());
  LOG_INFO << conn->name() << " discards " << msg.size()
           << " bytes received at " << time.toString();
}

这里直接在onConnect回调操作,onMessage忽略,不起作用


3)time

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

唯一不同的就是这个函数,很简单。不解释。

4)echo

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

5)chargen----char genarator?

#ifndef MUDUO_EXAMPLES_SIMPLE_CHARGEN_CHARGEN_H
#define MUDUO_EXAMPLES_SIMPLE_CHARGEN_CHARGEN_H
#include <muduo/net/TcpServer.h>
// RFC 864
class ChargenServer
{
 public:
  ChargenServer(muduo::net::EventLoop* loop,
                const muduo::net::InetAddress& listenAddr,
                bool print = false);
  void start();
 private:
  void onConnection(const muduo::net::TcpConnectionPtr& conn);
  void onMessage(const muduo::net::TcpConnectionPtr& conn,
                 muduo::net::Buffer* buf,
                 muduo::Timestamp time);
//多了这个回调函数
  void onWriteComplete(const muduo::net::TcpConnectionPtr& conn);
  void printThroughput();
  muduo::net::EventLoop* loop_;
  muduo::net::TcpServer server_;
  muduo::string message_;
  int64_t transferred_;
  muduo::Timestamp startTime_;
};
#endif  // MUDUO_EXAMPLES_SIMPLE_CHARGEN_CHARGEN_H
#include "chargen.h"
#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
#include <boost/bind.hpp>
#include <stdio.h>
using namespace muduo;
using namespace muduo::net;
ChargenServer::ChargenServer(EventLoop* loop,
                             const InetAddress& listenAddr,
                             bool print)
  : loop_(loop),
    server_(loop, listenAddr, "ChargenServer"),
    transferred_(0),
    startTime_(Timestamp::now())
{
  server_.setConnectionCallback(
      boost::bind(&ChargenServer::onConnection, this, _1));
  server_.setMessageCallback(
      boost::bind(&ChargenServer::onMessage, this, _1, _2, _3));
  server_.setWriteCompleteCallback(
      boost::bind(&ChargenServer::onWriteComplete, this, _1));
  if (print)
  {
    loop->runEvery(3.0, boost::bind(&ChargenServer::printThroughput, this));
  }
  string line;
  for (int i = 33; i < 127; ++i)//ascii编码
  {
    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);//屏蔽nagle算法
    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_);//一发送完毕,又接着发
}
//每3秒打印一次
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;
}

timeclient

#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 <boost/bind.hpp>
#include <utility>
#include <stdio.h>
#include <unistd.h>
using namespace muduo;
using namespace muduo::net;
//了解client的用法
class TimeClient : boost::noncopyable//作者都喜欢加上这个继承。。
{
 public:
  TimeClient(EventLoop* loop, const InetAddress& serverAddr)
    : loop_(loop),
      client_(loop, serverAddr, "TimeClient")//所有的都用上了“名字服务”
  {
    client_.setConnectionCallback(
        boost::bind(&TimeClient::onConnection, this, _1));
    client_.setMessageCallback(
        boost::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)
  {//了解作者这个Buffer对应的一些操作
    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(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]);
  }
}

chargenclient,无任何额外操作

#include "../chargen/chargen.h"
#include "../daytime/daytime.h"
#include "../discard/discard.h"
#include "../echo/echo.h"
#include "../time/time.h"
#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>
using namespace muduo;
using namespace muduo::net;
int main()
{
  LOG_INFO << "pid = " << getpid();
  EventLoop loop;  // one loop shared by multiple servers
  ChargenServer chargenServer(&loop, InetAddress(2019));
  chargenServer.start();
  DaytimeServer daytimeServer(&loop, InetAddress(2013));
  daytimeServer.start();
  DiscardServer discardServer(&loop, InetAddress(2009));
  discardServer.start();
  EchoServer echoServer(&loop, InetAddress(2007));
  echoServer.start();
  TimeServer timeServer(&loop, InetAddress(2037));
  timeServer.start();
  loop.loop();
}

可以知道,多个server时,怎么写程序。