1.五个简单TCP协议
1)discard--丢弃所有收到的数据
#include "discard.h" #include#include 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// 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#include 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#include 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// 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#include #include 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(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// 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#include #include #include 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 (transferred_)/time/1024/1024); transferred_ = 0; startTime_ = endTime; }
timeclient
#include#include #include #include #include #include #include #include #include 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 (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#include 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时,怎么写程序。