TcpServer类介绍[4-2]

说明:

当上层初始化TcpServer之后:

由于初始化TcpServer里面,new Acceptor 这里面会建立socket 并绑定本地addr,epoll中关注该socket的读事件;由于这里给Acceptor 注册TcpServer::newConnection函数,因此当监听套接字发生读事件时候执行TcpServer::newConnection函数;


当上层接着调用TcpServer::start()该函数中调用Acceptor::listen 之后

当新客户连接时候则调用TcpServer::newConnection 函数,该函数里面来一个客户端则new一个 TcpConnection 对象, 接着给该客户端注册回调函数;


TcpServer.h

#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;
 enum Option
 {
   kNoReusePort,
   kReusePort,
 };


 //TcpServer(EventLoop* loop, const InetAddress& listenAddr);
 TcpServer(EventLoop* loop,
           const InetAddress& listenAddr,
           const string& nameArg,
           Option option = kNoReusePort);
 ~TcpServer();  // force out-line dtor, for scoped_ptr members.


 const string& hostport() const { return hostport_; }
 const string& name() const { return name_; }
 EventLoop* getLoop() const { return loop_; }


 /// 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_;
 
 bool started_;
 // always in loop thread
 int nextConnId_;
 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;


/*
new Acceptor 这里面会建立socket 并绑定本地addr;
给Acceptor 注册TcpServer::newConnection函数;
当该层调用Acceptor::listen 后,当新客户连接时候则调用
TcpServer::newConnection 函数;

*/
TcpServer::TcpServer(EventLoop* loop,
                     const InetAddress& listenAddr,
                     const string& nameArg,
                     Option option)
  : loop_(CHECK_NOTNULL(loop)),
    hostport_(listenAddr.toIpPort()),
    name_(nameArg),
    acceptor_(new Acceptor(loop, listenAddr, option == kReusePort)),
    threadPool_(new EventLoopThreadPool(loop)),
    connectionCallback_(defaultConnectionCallback),
    messageCallback_(defaultMessageCallback),
    started_(false),
    nextConnId_(1)
{
  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);
}




/*
启动线程池;
利用evfd 通知主线程epoll 去执行Acceptor::listen

*/
void TcpServer::start()
{
 if (!started_)
 {
   started_ = true;
   threadPool_->start(threadInitCallback_);
 }


 if (!acceptor_->listenning())
 {
   loop_->runInLoop(
       boost::bind(&Acceptor::listen, get_pointer(acceptor_)));
 }
}




/*
当新客户连接时候,Acceptor 类中会调用该层给设置的回调函数
newConnection;
一个客户端对应一个 TcpConnection 对象, 接着给该客户端注册回调函数;

*/
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
  loop_->assertInLoopThread();
  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(ioLoop,
                                          connName,
                                          sockfd,
                                          localAddr,
                                          peerAddr));
  connections_[connName] = conn;
  conn->setConnectionCallback(connectionCallback_);
  conn->setMessageCallback(messageCallback_);
  conn->setWriteCompleteCallback(writeCompleteCallback_);
  conn->setCloseCallback(
      boost::bind(&TcpServer::removeConnection, this, _1)); // FIXME: unsafe
  ioLoop->runInLoop(boost::bind(&TcpConnection::connectEstablished, conn));
}




void TcpServer::removeConnection(const TcpConnectionPtr& conn)
{
  // FIXME: unsafe
  loop_->runInLoop(boost::bind(&TcpServer::removeConnectionInLoop, this, conn));
}


void TcpServer::removeConnectionInLoop(const TcpConnectionPtr& conn)
{
  loop_->assertInLoopThread();
  LOG_INFO << "TcpServer::removeConnectionInLoop [" << name_
           << "] - connection " << conn->name();
  size_t n = connections_.erase(conn->name());
  (void)n;
  assert(n == 1);
  EventLoop* ioLoop = conn->getLoop();
  ioLoop->queueInLoop(
      boost::bind(&TcpConnection::connectDestroyed, conn));
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,你想了解如何使用C++编写一个TCP服务器,我可以为你介绍一些基本的步骤。 首先,你需要了解TCP协议的基本知识,包括TCP连接的建立、数据的传输和断开连接等。然后,你需要选择一个合适的C++网络编程库,常用的有Boost.Asio、Poco、ACE等,这些库都提供了TCP服务器的实现。 以Boost.Asio库为例,以下是一个简单的TCP服务器的代码示例: ```c++ #include <boost/asio.hpp> #include <iostream> using boost::asio::ip::tcp; int main() { try { boost::asio::io_context io_context; tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 12345)); while (true) { tcp::socket socket(io_context); acceptor.accept(socket); std::string message = "Hello, world!"; boost::system::error_code error; boost::asio::write(socket, boost::asio::buffer(message), error); if (error) { std::cerr << "Error: " << error.message() << std::endl; } } } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << std::endl; } return 0; } ``` 这个例子创建了一个TCP服务器,监听端口号为12345。当有客户端连接时,服务器会发送一条简单的消息“Hello, world!”给客户端。 这个例子使用了Boost.Asio库中的io_context、tcp::acceptor和tcp::socket等。其中,io_context是Boost.Asio库中的核心,负责管理所有的异步IO操作,tcp::acceptor用于监听客户端连接请求,tcp::socket用于处理客户端连接和数据传输。 当有客户端连接时,服务器会创建一个新的tcp::socket对象,并将其传递给acceptor.accept()函数,等待客户端连接。一旦客户端连接成功,服务器就会发送一条消息给客户端,并关闭连接。 当然,这只是一个简单的示例代码,实际的TCP服务器需要处理更多的细节和错误情况。你需要根据自己的实际需求,对代码进行进一步的改进和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值