TcpServerTcpConnection(34)

来源:互联网 发布:知远战略与防务研究所 编辑:程序博客网 时间:2024/06/02 11:23
  1. Acceptor类的主要功能是socket、bind、listen

  2. 一般来说,在上层应用程序中,我们不直接使用Acceptor,而是把它作为TcpServer的成员

  3. TcpServer还包含了一个TcpConnection列表

  4. TcpConnection与Acceptor类似,有两个重要的数据成员,Socket与Channel


时序图






TcpServer头文件

TcpServer.h

// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is a public header file, it must only include public header files.#ifndef MUDUO_NET_TCPSERVER_H#define MUDUO_NET_TCPSERVER_H#include <muduo/base/Types.h>#include <muduo/net/TcpConnection.h>#include <map>#include <boost/noncopyable.hpp>#include <boost/scoped_ptr.hpp>namespace muduo{namespace net{class Acceptor;class EventLoop;////// TCP server, supports single-threaded and thread-pool models.////// This is an interface class, so don't expose too much details.class TcpServer : boost::noncopyable{ public:  //typedef boost::function<void(EventLoop*)> ThreadInitCallback;  //TcpServer(EventLoop* loop, const InetAddress& listenAddr);  TcpServer(EventLoop* loop,            const InetAddress& listenAddr,            const string& nameArg);  ~TcpServer();  // force out-line dtor, for scoped_ptr members.  /*返回服务器的名称*/  const string& hostport() const { return hostport_; }   /*返回服务器的监听端口*/  const string& name() const { return name_; }  /// Starts the server if it's not listenning.  ///  /// It's harmless to call it multiple times.  /// Thread safe.  void start();  /// Set connection callback.  /// Not thread safe.  // 设置连接到来或者连接关闭回调函数  void setConnectionCallback(const ConnectionCallback& cb)  { connectionCallback_ = cb; }  /// Set message callback.  /// Not thread safe.  // 设置消息到来回调函数  void setMessageCallback(const MessageCallback& cb)  { messageCallback_ = cb; } private:  /// Not thread safe, but in loop  // Acceptor::handleRead函数中会回调用TcpServer::newConnection  // _1对应的是socket文件描述符,_2对应的是对等方的地址(InetAddress)  //应该还在IO线程里面  // newConnection和connectionCallback_都是连接回调函数,但是connectionCallback_   // 是给应用程序使用的,newConnection是库函数,不会暴露给用户。  // 其实就是newConnection函数主要负责注册connectionCallback_ 函数  void newConnection(int sockfd, const InetAddress& peerAddr);  typedef std::map<string, TcpConnectionPtr> ConnectionMap;  EventLoop* loop_;  // the acceptor's loop,不一定是连接所属的eventloop  const string hostport_;       // 服务端口  const string name_;           // 服务名  boost::scoped_ptr<Acceptor> acceptor_; // avoid revealing Acceptor  /*连接到来的回调函数*/  ConnectionCallback connectionCallback_;  /*消息到来的回调函数*/  MessageCallback messageCallback_;  bool started_; /*连接是否启动*/  // always in loop thread  int nextConnId_;              // 下一个连接ID  ConnectionMap connections_;   // 连接列表};}}#endif  // MUDUO_NET_TCPSERVER_H

TcpServer源文件

TcpServer.cc


// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/net/TcpServer.h>#include <muduo/base/Logging.h>#include <muduo/net/Acceptor.h>#include <muduo/net/EventLoop.h>//#include <muduo/net/EventLoopThreadPool.h>#include <muduo/net/SocketsOps.h>#include <boost/bind.hpp>#include <stdio.h>  // snprintfusing namespace muduo;using namespace muduo::net;TcpServer::TcpServer(EventLoop* loop,                     const InetAddress& listenAddr,                     const string& nameArg)  : loop_(CHECK_NOTNULL(loop)),    hostport_(listenAddr.toIpPort()),    name_(nameArg),    acceptor_(new Acceptor(loop, listenAddr)),    /*threadPool_(new EventLoopThreadPool(loop)),    connectionCallback_(defaultConnectionCallback),    messageCallback_(defaultMessageCallback),*/    started_(false),    nextConnId_(1){  // Acceptor::handleRead函数中会回调用TcpServer::newConnection  // _1对应的是socket文件描述符,_2对应的是对等方的地址(InetAddress)  acceptor_->setNewConnectionCallback(      boost::bind(&TcpServer::newConnection, this, _1, _2));}TcpServer::~TcpServer(){  loop_->assertInLoopThread();  LOG_TRACE << "TcpServer::~TcpServer [" << name_ << "] destructing";}// 该函数多次调用是无害的// 该函数可以跨线程调用void TcpServer::start(){  if (!started_)  {    started_ = true;  }  /*如果还没有被执行,那么让他在IO线程中执行listen函数*/  if (!acceptor_->listenning())  {    // get_pointer返回原生指针    loop_->runInLoop(        boost::bind(&Acceptor::listen, get_pointer(acceptor_)));  }}void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr){  loop_->assertInLoopThread();  char buf[32];  snprintf(buf, sizeof buf, ":%s#%d", hostport_.c_str(), nextConnId_);  ++nextConnId_;  string connName = name_ + buf;  LOG_INFO << "TcpServer::newConnection [" << name_           << "] - new connection [" << connName           << "] from " << peerAddr.toIpPort();  InetAddress localAddr(sockets::getLocalAddr(sockfd));  // FIXME poll with zero timeout to double confirm the new connection  // FIXME use make_shared if necessary  /*构建一个连接对象*/  TcpConnectionPtr conn(new TcpConnection(loop_,                                          connName,                                          sockfd,                                          localAddr,                                          peerAddr));  connections_[connName] = conn;  conn->setConnectionCallback(connectionCallback_);  conn->setMessageCallback(messageCallback_);  conn->connectEstablished();}




TcpConnection头文件

TcpConnection.h


// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is a public header file, it must only include public header files.#ifndef MUDUO_NET_TCPCONNECTION_H#define MUDUO_NET_TCPCONNECTION_H#include <muduo/base/Mutex.h>#include <muduo/base/StringPiece.h>#include <muduo/base/Types.h>#include <muduo/net/Callbacks.h>//#include <muduo/net/Buffer.h>#include <muduo/net/InetAddress.h>//#include <boost/any.hpp>#include <boost/enable_shared_from_this.hpp>#include <boost/noncopyable.hpp>#include <boost/scoped_ptr.hpp>#include <boost/shared_ptr.hpp>namespace muduo{namespace net{class Channel;class EventLoop;class Socket;////// TCP connection, for both client and server usage.////// This is an interface class, so don't expose too much details.class TcpConnection : boost::noncopyable,                      public boost::enable_shared_from_this<TcpConnection>{ public:  /// Constructs a TcpConnection with a connected sockfd  ///  /// User should not create this object.  TcpConnection(EventLoop* loop,                const string& name,                int sockfd,                const InetAddress& localAddr,                const InetAddress& peerAddr);  ~TcpConnection();  EventLoop* getLoop() const { return loop_; }  const string& name() const { return name_; }  const InetAddress& localAddress() { return localAddr_; }  const InetAddress& peerAddress() { return peerAddr_; }  bool connected() const { return state_ == kConnected; }  void setConnectionCallback(const ConnectionCallback& cb)  { connectionCallback_ = cb; }  void setMessageCallback(const MessageCallback& cb)  { messageCallback_ = cb; }  // called when TcpServer accepts a new connection  void connectEstablished();   // should be called only once private:  enum StateE { /*kDisconnected, */kConnecting, kConnected/*, kDisconnecting*/ };  void handleRead(Timestamp receiveTime);  void setState(StateE s) { state_ = s; }  EventLoop* loop_;         // 所属EventLoop  string name_;             // 连接名  /*连接状态*/  StateE state_;  // FIXME: use atomic variable  // we don't expose those classes to client.  boost::scoped_ptr<Socket> socket_;  boost::scoped_ptr<Channel> channel_;  InetAddress localAddr_;  InetAddress peerAddr_;  /*连接套接字的回调函数*/  ConnectionCallback connectionCallback_;  /*消息被读到应用层后的回调函数*/  MessageCallback messageCallback_;};typedef boost::shared_ptr<TcpConnection> TcpConnectionPtr;}}#endif  // MUDUO_NET_TCPCONNECTION_H


TcpConnection源文件

TcpConnection.cc


// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)#include <muduo/net/TcpConnection.h>#include <muduo/base/Logging.h>#include <muduo/net/Channel.h>#include <muduo/net/EventLoop.h>#include <muduo/net/Socket.h>#include <muduo/net/SocketsOps.h>#include <boost/bind.hpp>#include <errno.h>#include <stdio.h>using namespace muduo;using namespace muduo::net;/*void muduo::net::defaultConnectionCallback(const TcpConnectionPtr& conn){  LOG_TRACE << conn->localAddress().toIpPort() << " -> "            << conn->peerAddress().toIpPort() << " is "            << (conn->connected() ? "UP" : "DOWN");}void muduo::net::defaultMessageCallback(const TcpConnectionPtr&,                                        Buffer* buf,                                        Timestamp){  buf->retrieveAll();}*/TcpConnection::TcpConnection(EventLoop* loop,                             const string& nameArg,                             int sockfd,                             const InetAddress& localAddr,                             const InetAddress& peerAddr)  : loop_(CHECK_NOTNULL(loop)),    name_(nameArg),    state_(kConnecting),    socket_(new Socket(sockfd)),    channel_(new Channel(loop, sockfd)),    localAddr_(localAddr),    peerAddr_(peerAddr)/*,    highWaterMark_(64*1024*1024)*/{  // 通道可读事件到来的时候,回调TcpConnection::handleRead,_1是事件发生时间  channel_->setReadCallback(      boost::bind(&TcpConnection::handleRead, this, _1));  LOG_DEBUG << "TcpConnection::ctor[" <<  name_ << "] at " << this            << " fd=" << sockfd;  socket_->setKeepAlive(true);}TcpConnection::~TcpConnection(){  LOG_DEBUG << "TcpConnection::dtor[" <<  name_ << "] at " << this            << " fd=" << channel_->fd();}void TcpConnection::connectEstablished(){  //断言在eventloop IO线程中  loop_->assertInLoopThread();  //断言还没有连接  assert(state_ == kConnecting);  setState(kConnected);  channel_->tie(shared_from_this());  /*如果连接成功,则关注可读事件*/  channel_->enableReading(); // TcpConnection所对应的通道加入到Poller关注  connectionCallback_(shared_from_this());}void TcpConnection::handleRead(Timestamp receiveTime){  /*  loop_->assertInLoopThread();  int savedErrno = 0;  ssize_t n = inputBuffer_.readFd(channel_->fd(), &savedErrno);  if (n > 0)  {    messageCallback_(shared_from_this(), &inputBuffer_, receiveTime);  }  else if (n == 0)  {    handleClose();  }  else  {    errno = savedErrno;    LOG_SYSERR << "TcpConnection::handleRead";    handleError();  }  */  loop_->assertInLoopThread();  char buf[65536];  ssize_t n = ::read(channel_->fd(), buf, sizeof buf);  messageCallback_(shared_from_this(), buf, n);}





CallBack源文件

CallBack.cc


// Copyright 2010, Shuo Chen.  All rights reserved.// http://code.google.com/p/muduo///// Use of this source code is governed by a BSD-style license// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)//// This is a public header file, it must only include public header files.#ifndef MUDUO_NET_CALLBACKS_H#define MUDUO_NET_CALLBACKS_H#include <boost/function.hpp>#include <boost/shared_ptr.hpp>#include <muduo/base/Timestamp.h>namespace muduo{/*// Adapted from google-protobuf stubs/common.h// see License in muduo/base/Types.htemplate<typename To, typename From>inline ::boost::shared_ptr<To> down_pointer_cast(const ::boost::shared_ptr<From>& f) {  if (false) {    implicit_cast<From*, To*>(0);  }#ifndef NDEBUG  assert(f == NULL || dynamic_cast<To*>(get_pointer(f)) != NULL);#endif  return ::boost::static_pointer_cast<To>(f);}*/namespace net{// All client visible callbacks go here./*class Buffer;*/class TcpConnection;typedef boost::shared_ptr<TcpConnection> TcpConnectionPtr;typedef boost::function<void()> TimerCallback;typedef boost::function<void (const TcpConnectionPtr&)> ConnectionCallback;/*typedef boost::function<void (const TcpConnectionPtr&)> CloseCallback;typedef boost::function<void (const TcpConnectionPtr&)> WriteCompleteCallback;typedef boost::function<void (const TcpConnectionPtr&, size_t)> HighWaterMarkCallback;// the data has been read to (buf, len)typedef boost::function<void (const TcpConnectionPtr&,                              Buffer*,                              Timestamp)> MessageCallback;void defaultConnectionCallback(const TcpConnectionPtr& conn);void defaultMessageCallback(const TcpConnectionPtr& conn,                            Buffer* buffer,                            Timestamp receiveTime);                            */typedef boost::function<void (const TcpConnectionPtr&,                              const char* data,                              ssize_t len)> MessageCallback;}}#endif  // MUDUO_NET_CALLBACKS_H




测试程序1

#include <muduo/net/TcpServer.h>#include <muduo/net/EventLoop.h>#include <muduo/net/InetAddress.h>#include <stdio.h>/*这个程序主要用来测试TcpServer、TcpConnection 由于这里的TcpServer还没有实现关闭的事件处理,所以当对等放关闭时,服务器会一直处于高电平状态,也就是说会一直触发**/using namespace muduo;using namespace muduo::net;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());  }}void onMessage(const TcpConnectionPtr& conn,               const char* data,               ssize_t len){  printf("onMessage(): received %zd bytes from connection [%s]\n",         len, conn->name().c_str());}int main(){  printf("main(): pid = %d\n", getpid());  InetAddress listenAddr(8888);  EventLoop loop;  TcpServer server(&loop, listenAddr, "TestServer");  server.setConnectionCallback(onConnection);  server.setMessageCallback(onMessage);  server.start();  loop.loop();}

程序输出:

客户端


aaahuiahsdui crosoft Telnet Client????????haracter is 'CTRL+]'sadasdasduhasuidhuiahsdiahsdjksdjfhsdiohahsoidoasudguagsdhjgashjdgajhksdasdasdsadMicrosoft Telnet> quitC:\Users\LaoHan>

服务器端

^Cubuntu@ubuntu-virtual-machine:~/pro/33/jmuduo$ ../build/debug/bin/reactor_test08 main(): pid = 606620131023 01:08:39.593827Z  6066 TRACE updateChannel fd = 4 events = 3 - EPollPoller.cc:10420131023 01:08:39.594123Z  6066 TRACE EventLoop EventLoop created 0xBFBEBEDC in thread 6066 - EventLoop.cc:6220131023 01:08:39.594172Z  6066 TRACE updateChannel fd = 5 events = 3 - EPollPoller.cc:10420131023 01:08:39.594331Z  6066 TRACE updateChannel fd = 6 events = 3 - EPollPoller.cc:10420131023 01:08:39.594387Z  6066 TRACE loop EventLoop 0xBFBEBEDC start looping - EventLoop.cc:9420131023 01:08:43.065719Z  6066 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:43.066560Z  6066 TRACE printActiveChannels {6: IN }  - EventLoop.cc:25720131023 01:08:43.066665Z  6066 INFO  TcpServer::newConnection [TestServer] - new connection [TestServer:0.0.0.0:8888#1] from 172.21.95.221:50007 - TcpServer.cc:7420131023 01:08:43.066762Z  6066 DEBUG TcpConnection TcpConnection::ctor[TestServer:0.0.0.0:8888#1] at 0x9D80468 fd=8 - TcpConnection.cc:5620131023 01:08:43.066802Z  6066 TRACE updateChannel fd = 8 events = 3 - EPollPoller.cc:104onConnection(): new connection [TestServer:0.0.0.0:8888#1] from 172.21.95.221:5000720131023 01:08:43.845782Z  6066 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:43.845853Z  6066 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 1 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:44.122627Z  6066 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:44.122695Z  6066 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 1 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:44.306479Z  6066 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:44.306545Z  6066 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 1 bytes from connection [TestServer:0.0.0.0:8888#1]onMessage(): received 0 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:23.429136Z  6063 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:23.429156Z  6063 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 0 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:23.429186Z  6063 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:23.429205Z  6063 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 0 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:23.429235Z  6063 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:23.429253Z  6063 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 0 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:23.429283Z  6063 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:23.429302Z  6063 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 0 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:23.429332Z  6063 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:23.429351Z  6063 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 0 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:23.429381Z  6063 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:23.429399Z  6063 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 0 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:23.429447Z  6063 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:23.429466Z  6063 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 0 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:23.429497Z  6063 TRACE poll 1 events happended - EPollPoller.cc:6520131023 01:08:23.429515Z  6063 TRACE printActiveChannels {8: IN }  - EventLoop.cc:257onMessage(): received 0 bytes from connection [TestServer:0.0.0.0:8888#1]20131023 01:08:23.429545Z  6063 TRACE poll 1 events happended - EPollPoller.cc:65



测试程序2

#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)    : loop_(loop),      server_(loop, listenAddr, "TestServer")  {    server_.setConnectionCallback(        boost::bind(&TestServer::onConnection, this, _1));    server_.setMessageCallback(        boost::bind(&TestServer::onMessage, this, _1, _2, _3));  }  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());    }  }  void onMessage(const TcpConnectionPtr& conn,                   const char* data,                   ssize_t len)  {    printf("onMessage(): received %zd bytes from connection [%s]\n",           len, conn->name().c_str());  }  EventLoop* loop_;  TcpServer server_;};int main(){  printf("main(): pid = %d\n", getpid());  InetAddress listenAddr(8888);  EventLoop loop;  TestServer server(&loop, listenAddr);  server.start();  loop.loop();}



原创粉丝点击