net8. 服务器类——TcpServer

TcpServer类

  1. TcpServer中封装了EventLoopThreadPool,因此TcpServer中的EventLoop对象为main Reactor,EventLoopThreadPool为sub Reactor。当新建连接到达后,TcpServer创建一个新的TcpConnection对象来保存这个连接,设置这个新连接的回调函数,之后在EventLoopThreadPool中取一个EventLoop对象来作为这个新连接的reactor。
  2. 在TcpServer中,建立连接描述符和TcpConnection之间的关系,通过stl中map来实现,map<int,TcpConnectionPtr>这样可以高效的查找,删除,插入操作。
  3. TcpServer本身有一个EventLoop,主要用于对接受连接事件的监听,EventLoopPool也为TcpServer的成员,使用轮转法为每一个新的TcpConnection选择EventLoop。
  4. TcpServer类用来统一管理Acceptor和TcpConnection,为TcpConnection和Acceptor这两个类注册回调函数。

数据成员:

EventLoop* loop_:loop_是acceptor_对象所属的EventLoop
const string hostport_:服务端口
const string name_:服务名
boost::scoped_ptr<Acceptor> acceptor_:创建、绑定、监听套接字的acceptor_对象
boost::scoped_ptr<EventLoopThreadPool> threadPool_:线程池对象
ConnectionCallback connectionCallback_:连接到来的回调函数connectionCallback_,ConnectionCallback定义在Callbacks.h中
MessageCallback messageCallback_:消息到来的回调函数messageCallback_,MessageCallback定义在Callbacks.h中
WriteCompleteCallback writeCompleteCallback_:数据发送完毕时的回调此函数writeCompleteCallback_
ThreadInitCallback threadInitCallback_:IO线程池中的线程在进入事件循环前,会回调用此函数
bool started_:连接是否已经启动了
int nextConnId_:下一个连接的ID
ConnectionMap connections_:连接列表

typedef

typedef std::map<string, TcpConnectionPtr> ConnectionMap

成员函数:

TcpServer(EventLoop* loop,const InetAddress& listenAddr,const string& nameArg):构造函数,需要传递一个回调函数
~TcpServer():析构函数
const string& hostport() const:返回服务端口
const string& name() const:返回服务名
void start():启动函数
void setConnectionCallback(const ConnectionCallback& cb):设置连接到来或者连接关闭时的回调函数
void setMessageCallback(const MessageCallback& cb):设置消息到来时的回调函数
void setWriteCompleteCallback(const WriteCompleteCallback& cb):设置数据发送完毕时的回调此函数
void newConnection(int sockfd, const InetAddress& peerAddr):连接到来的时候会回调的一个函数
void removeConnection(const TcpConnectionPtr& conn):连接关闭时调用的函数
void removeConnectionInLoop(const TcpConnectionPtr& conn):连接关闭时被removeConnection()调用

TcpServer.h

// 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;
class EventLoopThreadPool;

///
/// 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_; }

  /// Set the number of threads for handling input.
  ///
  /// Always accepts new connection in loop's thread.
  /// Must be called before @c start
  /// @param numThreads
  /// - 0 means all I/O in loop's thread, no thread will created.
  ///   this is the default value.
  /// - 1 means all I/O in another thread.
  /// - N means a thread pool with N threads, new connections
  ///   are assigned on a round-robin basis.
  void setThreadNum(int numThreads);
  void setThreadInitCallback(const ThreadInitCallback& cb)
  { threadInitCallback_ = cb; }

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

  /// Set write complete callback.
  /// Not thread safe.
  void setWriteCompleteCallback(const WriteCompleteCallback& cb)
  { writeCompleteCallback_ = cb; }


 private:
  /// Not thread safe, but in loop
  void newConnection(int sockfd, const InetAddress& peerAddr);
  /// Thread safe.
  void removeConnection(const TcpConnectionPtr& conn);
  /// Not thread safe, but in loop
  void removeConnectionInLoop(const TcpConnectionPtr& conn);

  typedef std::map<string, TcpConnectionPtr> ConnectionMap;

  EventLoop* loop_;  // the acceptor loop
  const string hostport_;		// 服务端口
  const string name_;			// 服务名
  boost::scoped_ptr<Acceptor> acceptor_; // avoid revealing Acceptor
  boost::scoped_ptr<EventLoopThreadPool> threadPool_;
  ConnectionCallback connectionCallback_;
  MessageCallback messageCallback_;
  WriteCompleteCallback writeCompleteCallback_;		// 数据发送完毕,会回调此函数
  ThreadInitCallback threadInitCallback_;	// IO线程池中的线程在进入事件循环前,会回调用此函数
  bool started_;
  // always in loop thread
  int nextConnId_;				// 下一个连接ID
  ConnectionMap connections_;	// 连接列表
};

}
}

#endif  // MUDUO_NET_TCPSERVER_H

TcpServer.cc

#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>  // snprintf

using 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";

  for (ConnectionMap::iterator it(connections_.begin());
      it != connections_.end(); ++it)
  {
    TcpConnectionPtr conn = it->second;
    it->second.reset();		// 释放当前所控制的对象,引用计数减一
    conn->getLoop()->runInLoop(
      boost::bind(&TcpConnection::connectDestroyed, conn));
    conn.reset();			// 释放当前所控制的对象,引用计数减一
  }
}

void TcpServer::setThreadNum(int numThreads)
{
  assert(0 <= numThreads);
  threadPool_->setThreadNum(numThreads);
}

// 该函数多次调用是无害的
// 该函数可以跨线程调用
void TcpServer::start()
{
  if (!started_)
  {
    started_ = true;
	threadPool_->start(threadInitCallback_);
  }

  if (!acceptor_->listenning())
  {
	// get_pointer返回原生指针
    loop_->runInLoop(
        boost::bind(&Acceptor::listen, get_pointer(acceptor_)));
  }
}

void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
  loop_->assertInLoopThread();
  // 按照轮叫的方式选择一个EventLoop
  EventLoop* ioLoop = threadPool_->getNextLoop();
  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));*/

  TcpConnectionPtr conn(new TcpConnection(ioLoop,
                                          connName,
                                          sockfd,
                                          localAddr,
                                          peerAddr));

  LOG_TRACE << "[1] usecount=" << conn.use_count();
  connections_[connName] = conn;
  LOG_TRACE << "[2] usecount=" << conn.use_count();
  conn->setConnectionCallback(connectionCallback_);
  conn->setMessageCallback(messageCallback_);
  conn->setWriteCompleteCallback(writeCompleteCallback_);

  conn->setCloseCallback(
      boost::bind(&TcpServer::removeConnection, this, _1));

  // conn->connectEstablished();
  ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
  LOG_TRACE << "[5] usecount=" << conn.use_count();

}

void TcpServer::removeConnection(const TcpConnectionPtr& conn)
{
	/*
  loop_->assertInLoopThread();
  LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_
           << "] - connection " << conn->name();


  LOG_TRACE << "[8] usecount=" << conn.use_count();
  size_t n = connections_.erase(conn->name());
  LOG_TRACE << "[9] usecount=" << conn.use_count();

  (void)n;
  assert(n == 1);
  
  loop_->queueInLoop(
      boost::bind(&TcpConnection::connectDestroyed, conn));
  LOG_TRACE << "[10] usecount=" << conn.use_count();
  */

  loop_->runInLoop(boost::bind(&TcpServer::removeConnectionInLoop, this, conn));

}

void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn)
{
  loop_->assertInLoopThread();
  LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_
           << "] - connection " << conn->name();


  LOG_TRACE << "[8] usecount=" << conn.use_count();
  size_t n = connections_.erase(conn->name());
  LOG_TRACE << "[9] usecount=" << conn.use_count();

  (void)n;
  assert(n == 1);
  
  EventLoop* ioLoop = conn->getLoop();
  ioLoop->queueInLoop(
      boost::bind(&TcpConnection::connectDestroyed, conn));

  //loop_->queueInLoop(
  //    boost::bind(&TcpConnection::connectDestroyed, conn));
  LOG_TRACE << "[10] usecount=" << conn.use_count();


  
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用VB实现客户服务器(TCP/IP)编程实例,可以按照以下步骤: 1. 首先,在Server端,通过VB编写代码以创建一个TCP/IP服务器。可以使用TcpListener类来创建监听器对象,指定服务器的IP地址和端口号。然后,使用Accept方法来等待客户端连接,并在连接成功时返回一个TcpClient对象。 2. 接下来,在Client端,同样通过VB编写代码来创建一个TCP/IP客户端。可以使用TcpClient类来创建一个客户端对象,并指定要连接的服务器的IP地址和端口号。 3. 在Server端,可以使用TcpClient对象的GetStream方法获取一个网络流对象,用于与客户端进行通信。通过网络流对象,可以使用StreamReader和StreamWriter类来读取和写入数据。 4. 在Client端,同样可以使用TcpClient对象的GetStream方法获取一个网络流对象,用于与服务器进行通信。通过网络流对象,也可以使用StreamReader和StreamWriter类来读取和写入数据。 5. 在Server端,可以使用一个无限循环来接收和处理客户端发送的消息。使用StreamReader的ReadLine方法读取客户端发送的消息,并使用StreamWriter的WriteLine方法向客户端发送消息。 6. 在Client端,可以使用StreamReader的ReadLine方法读取服务器发送的消息,并使用StreamWriter的WriteLine方法向服务器发送消息。 7. 最后,在Server端和Client端的适当位置,需要使用TcpClient对象的Close方法来关闭连接。 通过以上步骤,就可以使用VB实现一个简单的客户服务器(TCP/IP)编程实例。其中,Server端负责监听、接受和处理客户端连接,而Client端则负责与服务器建立连接并进行通信。使用网络流对象的StreamReader和StreamWriter类,可以实现双方的数据传输。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值