Muduo网络库的实现TCP网络库(七)

本文详细介绍了Muduo网络库中的Acceptor类和TCP连接管理,包括Acceptor如何处理新连接,以及TcpConnection和TcpServer类的设计。TcpConnection使用shared_ptr管理,处理连接的建立和断开,而TcpServer负责管理和维护TcpConnection对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码下载以及安装点击链接https://blog.youkuaiyun.com/YoungSusie/article/details/90021742

分类 Muduo网络库编程 学习笔记

Reactor 事件处理框架如图
在这里插入图片描述
不同于传统的Reactor,将timers 做成循环中单独的一步,muduo将 timers 和IO handlers 视为等同的。

1、Acceptor class

Acceptor class 用于 accept 新的TCP 连接, 并通过回调通知使用者,这是一个内部class , 供 Tcpserver 使用,Acceptor class 的生命期 由 Tcpserver 从 控制。
Acceptor class 的数据成员包括 Socket、Channel等。其中Socket 是一个RAII handle,封装 了socket 文件描述符的生命期。Acceptor 的socket 是listening socket,即server socket。acceptChannel 用于观察此socket 上的readable 事件,并且回调acceptor::handleRead(),handleRead()会调用accept 来接受新连接,并且回调用户的callback

Acceptor::listen() 函数的最后一步让 acceptChannel在socket 可读 的时候回调Acceptor::handleRead()。Acceptor::handleRead()会接受accept(),并且回调newConnectionCallback。

Acceptor::handleRead()的策略很简单,每次accept 一个socket,另外还有两种实现:一是每次循环accept,直到没有新的连接到达;另外一个是每次尝试accept N 个新连接。后面两种方法比较适合短链接。

1、InetAddress class 对 struct sockaddr_in 的简单封装
2、Socket class 套接字的封装
3、SocketsOps.cc 主要是Socket 相关处理的函数
4、Acceptor class 用于接受新的 tcp 连接。

2、TCP接受新连接

(1)TcpConnection class

TcpConnection class 是最复杂的class,这部分只是先实现这个class的一部分,TcpConnection class 是 唯一默认使用shared_ptr 来管理的class,也是唯一继承 enable_shared_from_this 的class,TcpConnection class 对象是短命对象,不同于 TcpServer 是长命对象。对于短命对象,其生命期的控制不一定完全被控制,例如:对方客户端断开了某个TCP socket ,其对应的服务端进程中的TcpConnection 对象(是一个堆对象)的生命也即将走到尽头。但是此时我们不能立刻 delete 这个对象,因为其他地方可能还持有其引用。用智能指针控制TcpConnection class 的生命期更安全。

TcpConnection 没有可以供用户直接调用的函数,TcpConnection class 有两个状态:连接与未连接。TcpConnection class 使用channel 来获得socket 上的IO 事件,它自己处理writeable 事件,将 readable(接收数据) 事件通过messagecallbak 传给客户,TcpConnection class 拥有自己的Tcp socket, 析构函数中自动关闭这个socket。

TcpConnection class 表示的是一次tcp连接,是不可再生的,一旦连接断开,这个对象就没用了。TcpConnection class 也没有发起连接的功能,其构造函数中的参数是已经建好连接的sockfd 。
==================================TcpConnection.h ====================================

#ifndef _TCPCONNECTION_H
#define _TCPCONNETCION_H

#include "InetAddress.h"


#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <boost/any.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>

class TcpConnection;
typedef boost::shared_ptr<TcpConnection> TcpConnectionPtr;
typedef boost::function<void (const TcpConnectionPtr&)> ConnectionCallback;
typedef boost::function<void (const TcpConnectionPtr&,const char* data,ssize_t len)> MessageCallback;

class Channel;
class EventLoop;
class Socket;

class TcpConnection : boost::noncopyable, public boost::enable_shared_from_this<TcpConnection>
{
  public:
	TcpConnection(EventLoop* loop, const std::string & name,int sockfd,
               const InetAddress & localAddr, const InetAddress & peerAddr);
	
	~TcpConnection();

	EventLoop* getLoop() const {return loop_;}
	const std::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;}

	void connectEstablished();

  private:
	enum StateE { kConnecting,kConnected, };

	void setState(StateE s) {state_ = s;}

	void handleRead();
	
	EventLoop * loop_;
	std::string name_;
	StateE state_;

	boost::scoped_ptr<Socket> socket_;
	boost::scoped_ptr<Channel> channel_;
	InetAddress localAddr_;
	InetAddress peerAddr_;
	ConnectionCallback connectionCallback_;
	MessageCallback messageCallback_;
};


#endif



==================================TcpConnection.cc ====================================

#include "TcpConnection.h"
#include "Channel.h"
#include "EventLoop.h"
#include "Socket.h"

#include <boost/bind.hpp>
#include <stdio.h>
#include <errno.h>

TcpConnection::TcpConnection(EventLoop * loop,const std::string & nameArg,int sockfd,
	const InetAddress & localAddr, const InetAddress & peerAddr)
	: loop_(loop),name_(nameArg),state_(kConnecting),
	socket_(new Socket(sockfd)),channel_(new Channel(loop,sockfd)),
	localAddr_(localAddr),peerAddr_(peerAddr)
{
		std::cout << "TcpConnection :: stor[" << name_ << "] at " << this << " fd = " << sockfd << std::endl; 
		channel_->setReadCallback(boost::bind(&TcpConnection::handleRead,this));
}


TcpConnection::~TcpConnection()
{
	std::cout << "TcpConnection::dtor[" << name_ << "] at " << this << " fd = " << channel_->fd() << std::endl;
}


void TcpConnection::connectEstablished()
{
	loop_->assertInLoopThread();
	assert(state_ == kConnecting);
	setState(kConnected);
	channel_->enableReading(); 
	connectionCallback_(shared_from_this());
}


void TcpConnection::handleRead()
{
	char buf[65536];
	ssize_t n = ::read(channel_->fd(),buf, sizeof buf);
	messageCallback_(shared_from_this(),buf,n);
}

目前TcpConnection class 只处理了建立连接,没有处理断开连接,后面再完善。

(2) TcpServer class

TcpServer class 的功能是管理accept 获得的 TcpConnection 。TcpServer class 是供用户直接使用的,生命期由用户控制,用户需要设置好callback,再调用start() 即可。

TcpServer class 的内部使用 acceptor 来获得新连接的fd。TcpServer 持有目前存活的TcpConnection 的 shared_ptr , 每个TcpConnection 对象有一个名字,这个名字是其所属的TcpServer 在创建 TcpConnection 对象时生成,名字是ConnectionMap 的 key,在新连接到来时,Acceptor 会回调newConnetion() ,后者会创建TcpConnection 对象,将它加入 ConnectionMap ,设置好callback,再调用TcpConnection-> connectEstablished() 。
==================================TcpServer.h ====================================

#ifndef _TCPSERVER_H
#define _TCPSERVER_H
#include "TcpConnection.h"

#include <map>

#include <boost/noncopyable.hpp>
#include <boost/scoped_ptr.hpp>

class Acceptor;
class EventLoop;

class TcpServer : boost::noncopyable
{
  public:
	TcpServer(EventLoop * loop, const InetAddress & listenAddr);
	~TcpServer();

	void start();

	void setConnectionCallback(const ConnectionCallback & cb)
	{ connectionCallback_ = cb;}
	

	void setMessageCallback(const MessageCallback & cb)
	{ messageCallback_ = cb;}

	
  private:
	void newConnection(int sockfd, const InetAddress & peerAddr); //不是线程安全的

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

	EventLoop * loop_;
	const std::string name_;

	boost::scoped_ptr<Acceptor> acceptor_;
	ConnectionCallback connectionCallback_;
	MessageCallback messageCallback_;
	bool started_;
	int nextConnId_;
	ConnectionMap connections_;
};

#endif

==================================TcpServer.cc ====================================


#include "TcpServer.h"
#include "Acceptor.h"
#include "EventLoop.h"
#include "SocketsOps.h"

#include <boost/bind.hpp>
#include <stdio.h>

TcpServer::TcpServer(EventLoop * loop, const InetAddress & listenAddr)
	:loop_(loop), name_(listenAddr.toHostPort()),
	 acceptor_(new Acceptor(loop, listenAddr)),
	 started_(false),nextConnId_(1)
{
        std::cout << "tcpserver init\n";
	acceptor_->setNewConnectionCallback(boost::bind(&TcpServer::newConnection,this,_1,_2));
}

TcpServer::~TcpServer()
{}

void TcpServer::start()
{
	std::cout << "tcpserver start\n";
	if(!started_)
	{		started_ = true;}
	if(!acceptor_->listening()) 
	{
		loop_->runInLoop(boost::bind(&Acceptor::listen,get_pointer(acceptor_)));
	}
	std::cout << "tcpserver start done\n";
}

void TcpServer::newConnection(int sockfd, const InetAddress & peerAddr)
{
	loop_->assertInLoopThread();
	char buf[32];
	snprintf(buf,sizeof buf, "#%d" , nextConnId_);
	++nextConnId_;
	std::string connName = name_ + buf;
	InetAddress localAddr(sockets::getLocalAddr(sockfd));
  	TcpConnectionPtr conn(
      			new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr));
  	connections_[connName] = conn;
  	conn->setConnectionCallback(connectionCallback_);
  	conn->setMessageCallback(messageCallback_);
  	conn->connectEstablished();
}


分类 Muduo网络库编程 学习笔记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值