天天看点

使用muduo库编写回射服务器echo

muduo是一个基于事件驱动的非阻塞网络库,采用C++和Boost库编写。

(一)使用muduo编写echo回射服务器

在github上下载muduo源码,使用里面的

build.sh

完成编译,查看这个脚本,可以设置debug版本还是release版本,并指定生成路径:默认是release,生成的库和头文件在

${HOME}/build/release-install

目录下,因为muduo是静态链接的C++程序库,因此使用的时候需要指定头文件目录,和库文件目录,并链接相应的静态库文件(

-lmuduo_net -lmuduo_base

)。

echo回射服务器函数我们很熟悉,大体步骤是:

1.创建套接字 socket

2.绑定端口 bind

3.监听套接字 listen

4.阻塞等待客户端连接 accept

5.连接建立accept返回,阻塞等待客户端消息 recv

6.回射消息到客户端 write

基于事件的非阻塞网络编程,是编写高性能并发网络服务器的主流模式,使用这种方式首先要转变一下上述步骤中的思路:把原来的“主动调用recv来接收数据,主动调用accept来接收连接,主动调用send来发送数据”,换成“注册一个收数据的回调,网络库收到数据会调用我,直接把数据提供给我,供我消费;注册一个接收连接的回调,网络库接受了新连接会回调我,供我使用;需要发送数据的时候,只管往连接中写,网络库会负责无阻塞地发送。”

关于怎么去使用epoll轮询,怎么使用线程池分发任务等细节,待后续阅读源码后再仔细学习。首先学会使用muduo库编写一个回射服务器echo程序。

1.1 直接编写回调函数

//  echo1/echo.cpp

#include <muduo/base/Logging.h>
#include <muduo/base/Timestamp.h>
#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/TcpConnection.h>

using namespace muduo;
using namespace muduo::net;

//accept的回调函数
void onConnection(const TcpConnectionPtr &conn)
{
    LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "
    << conn->localAddress().toIpPort() << " is "
    << (conn->connected() ? "UP" : "DOWN");
}

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

int main(int argc, const char *argv[])
{
    EventLoop loop;
    InetAddress addr("127.0.0.1", );//设置服务端IP/端口
    TcpServer server(&loop, addr, "echo");
    server.setConnectionCallback(&onConnection);//注册回调
    server.setMessageCallback(&onMessage);//注册回调
    server.start();
    loop.loop();
    return ;
}
           

1.2 面向对象的思路

另一个方法就是将回调函数的注册写到类的构造函数中,书中给出的示例如下:

//  echo2/echoserver.h

#ifndef __ECHOSERVER_H__
#define __ECHOSERVER_H__

#include <muduo/net/TcpServer.h>

// RFC 862
class EchoServer
{
    public:
        EchoServer(muduo::net::EventLoop* loop,
            const muduo::net::InetAddress& listenAddr);//构造函数

        void start();  // calls server_.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::TcpServer server_;
};

#endif
           
// echo2/echoserver.cpp

#include "echoserver.h"
#include <muduo/base/Logging.h>
#include <boost/bind.hpp>

// using namespace muduo;
// using namespace muduo::net;

EchoServer::EchoServer(muduo::net::EventLoop* loop, 
                    const muduo::net::InetAddress& listenAddr)
                    : server_(loop, listenAddr, "EchoServer")
    {
        server_.setConnectionCallback(
            boost::bind(&EchoServer::onConnection, this, _1));//注册回调
        server_.setMessageCallback(//注册回调
            boost::bind(&EchoServer::onMessage, this, _1, _2, _3));
    }

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

void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn)//回调函数编写
{
    LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "
    << conn->localAddress().toIpPort() << " is "
    << (conn->connected() ? "UP" : "DOWN");
}

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);
}
           
// echo2/echo2.cpp

#include "echoserver.h"

#include <muduo/base/Logging.h>
#include <muduo/net/EventLoop.h>

int main()
{
  LOG_INFO << "pid = " << getpid();
  muduo::net::EventLoop loop;
  muduo::net::InetAddress listenAddr();
  EchoServer server(&loop, listenAddr);
  server.start();
  loop.loop();
  return ;
}
           

1.3 编写Makefile

muduo是静态链接的C++程序库,需要在Makefile文件中特别指明头文件和库文件路径等。

PROGS+=echo1 echo2
CLEANFILES = core core.* *.core *.o temp.* *.out typescript* \
        *.lc *.lh *.bsdi *.sparc *.uw

MUDUO_DIRECTORY = ${HOME}/build/release-install
MUDUO_INCLUDE = $(MUDUO_DIRECTORY)/include
MUDUO_LIBRARY = $(MUDUO_DIRECTORY)/lib
OUTPUT=${PWD}/bin

all :${PROGS}



MAKE_BIN_DIR := $(shell mkdir -p $(OUTPUT) )

CXXFLAGS+=-g -std=c++ -I${MUDUO_INCLUDE}
LDFLAGS+=-L${MUDUO_LIBRARY} -lmuduo_net -lmuduo_base -lpthread -lrt

#所有的输出在bin目录下
echo1:echo1/echo.o
    ${CXX} ${CXXFLAGS}  -o ${OUTPUT}/[email protected]   $^  ${LDFLAGS}
    @rm echo1/*.o
echo2: echo2/echo2.o echo2/echoserver.o
    ${CXX} ${CXXFLAGS} -o ${OUTPUT}/[email protected]   $^  ${LDFLAGS}
    @rm echo2/*.o

clean:
    rm -rf ${OUTPUT} 


.PHONY: all clean
           

1.4 测试回射服务器echo

本地运行,使用

netcat

进行测试:

nc localhost 
           

服务器将回射键入的文本:

使用muduo库编写回射服务器echo

根据我们的回调函数,服务端也会有相应的信息:

使用muduo库编写回射服务器echo

(二)参考

1.《Linux多线程服务端编程 使用muduo C++网络库》

2.http://www.cnblogs.com/inevermore/p/4393309.html

继续阅读