muduo库的TcpServer和TcpConnection用法

(本文地址:LYanger的博客:http://blog.csdn.net/freeelinux/article/details/53574574


TcpServer是muduo库很重要的一个类,它结合TcpConnection、Acceptor构成了一套完整的对I/O触发事件的处理机制。那么它们具体是怎么工作的呢?

先来看一个例子:

#include <muduo/net/TcpServer.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>

#include <boost/bind.hpp>

#include <stdio.h>

using namespace muduo;
using namespace muduo::net;

class TestServer {
public:
    TestServer(EventLoop* loop, const InetAddress& listenAddr, int numThreads)
        : loop_(loop), 
          server_(loop, listenAddr, "TestServer"),
          numThreads_(numThreads){
        server_.setConnectionCallback(boost::bind(&TestServer::onConnection, this, _1));
        server_.setThreadNum(numThreads);
    }   

    void start(){
        server_.start();
    }   
private:
    void onConnection(const TcpConnectionPtr& conn){
        if(conn->connected()){
            printf("onConnection(): new connection [%s] from %s \n",
                    conn->name().c_str(),
                    conn->peerAddress().toIpPort().c_str());
        }   
  else{
            printf("onConnection() : connection [%s] is down\n",
                    conn->name().c_str());
        }           
    }   
    
    EventLoop* loop_;
    TcpServer server_;
    int numThreads_;
};  

int main()
{
    printf("main() : pid = %d\n", getpid());

    InetAddress listenAddr(8888);
    EventLoop loop;

    TestServer server(&loop, listenAddr, 4);
    server.start();

    loop.loop();
}

输出:


先不分析结构,我们来分析一下过程:

首先主函数中声明了一个InetAddress对象,构造参数是服务端的端口号,我们来看一下InetAddress的构造函数:

//仅仅指定port,不指定ip,则ip为INADDR_ANY(即0.0.0.0)
  explicit InetAddress(uint16_t port = 0, bool loopbackOnly = false, bool ipv6 = false);
具体实现截取ipv4部分是这样的:

InetAddress::InetAddress(uint16_t port, bool loopbackOnly, bool ipv6)
{
  if (ipv6)
  {
    ...
  }
  else
  {
    bzero(&addr_, sizeof addr_);
    addr_.sin_family = AF_INET;
    in_addr_t ip = loopbackOnly ? kInaddrLoopback : kInaddrAny; //INADDR_ANY 或者 INADDY_LOOPBACK
    addr_.sin_addr.s_addr = sockets::hostToNetwork32(ip);
    addr_.sin_port = sockets::hostToNetwork16(port);
  }
}

它起始就是我们编最简单socket程序时sockaddr_in结构体填充的一个封装。

然后主函数中声明了一个loop对象,EventLoop类的功能就不用说了,Reactor循环处理事件的一个封装。给出它的成员函数:

bool looping_; /* atomic */
  bool quit_; /* atomic and shared between threads, okay on x86, I guess. */
  bool eventHandling_; /* atomic */
  bool callingPendingFunctors_; /* atomic */
  int64_t iteration_;  
  const pid_t threadId_;   //当前所属对象线程id
  Timestamp pollReturnTime_;    //时间戳,poll返回的时间戳
  boost::scoped_ptr<Poller> poller_;  //poller对象
  boost::scoped_ptr<TimerQueue> timerQueue_;
  int wakeupFd_;     //用于eventfd
  // unlike in TimerQueue, which is an internal class,
  // we don't expose Channel to client.
  boost::scoped_ptr<Channel> wakeupChannel_;   //wakeupfd所对应的通道,该通道会纳入到poller来管理
  boost::any context_;

  // scratch variables
  ChannelList activeChannels_;   //Poller返回的活动通道,vector<channel*>类型
  Channel* currentActiveChannel_;   //当前正在处理的活动通道

  MutexLock mutex_;
  std::vector<Functor> pendingFunctors_; // @GuardedBy mutex_
我们来分析一下打开的描述符,接下来本文打开的描述符都用绿色标注。

1.首先poller_对象会打开文件描述符值为3的pollfd,一般是是epollfd。

2.打开timerfd,这和接下来的eventfd是muduo使用的较新的系统调用之一。

3.wakeupFd_,I/O线程自己和自己通信的eventfd。

4.server肯定会调用listen,所以将来肯定会打开Acceptor类的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值