muduo网络库源码解析 四

26 篇文章 1 订阅

这一章节我们首先来解析用到的socket的基础函数:

1、字节序转换函数封装为HostToNetwork16、HostToNetwork32类似命名,原函数为htons、htonl,封装后方便记忆与书写,头文件<netinet/in.h>

2、地址转换函数toHostPort和fromHostPort,用的是<arpa/inet.h>中的inet_pton和inet_ntop,p和n表示表达式和数值

3、设置文件描述符为non-blocking和close-on-exec函数:setNonBlockAndCloseOnExec,createNonblockingOrDie

4、地址类型转换函数,利用C++的类型转换函数:

const SA* sockaddr_cast(const struct sockaddr_in *addr)
{
	return reinterpret_cast<const SA*>(addr); 
}

SA* sockaddr_cast(struct sockaddr_in *addr)
{
	return reinterpret_cast<SA*>(addr);
}
5、bind、listen都进行了简单的封装,加上了处理失败的情况

6、accept进行了处理,如果不支持accept4函数,则调用setNonBlockAndCloseOnExec,将connfd设置为non-blocking和close-on-exec,否则直接调用accept4,该函数可以直接将connfd设置为non-blocking和close-on-exec

另外,muduo对socket也进行了封装,封装为Socket类,将socket的相关操作进行封装,比如bind、listen、accept,也提供了返回fd的接口。

下面我们来解析一下TCP建立的过程:


有了以上基础,我们可以来解析Acceptor类,该类是个内部类,供TcpServer使用,用于接受新连接,并通过回调通知使用者。该类比较简单,提供三个public成员函数:

void setNewConnectionCallback(const newConnectionCallback &cb)
{
	newConnectionCallback_ = cb;
}

bool listening() { return listening_; }
void listen();
第一个用于设置接受新连接的回调函数,第二个返回状态,第三个设置socket开始监听。
void Acceptor::listen()
{
	loop_->assertInLoopThread();
	listening_ = true;
	acceptSocket_.listen();
	acceptChannel_.enableReading();
}
利用Channel,将其加入Poller的监听队列里。

该类含有一个处理连接到来的函数,即handleRead:

void Acceptor::handleRead()
{
	loop_->assertInLoopThread();
	InetAddress peerAddr(0);
	int connfd = acceptSocket_.accept(&peerAddr);
	if (connfd > 0)
	{
		newConnectionCallback_(connfd, peerAddr);
	}
}
该函数是个私有类型,在构造函数里,会将此函数bind到Channel的readCallback_上,当对应的fd可读时,说明有新连接到来,即执行此回调函数


接着来解析TcpServer类,这个类是对用户开放,用于处理新建的TcpConnection。TcpServer类的核心函数有两个,都是私有:

void newConnection(int sockfd, const InetAddress& peerAddr);
void removeConnection(const TcpConnectionPtr &conn);
一个用来处理新建的连接,一个用来断开连接(被动关闭),相关的数据结构为:

typedef std::map<std::string, TcpConnectionPtr> ConnectionMap;
std::unique_ptr<Acceptor> acceptor_;
int nextConnId_;
ConnectionMap connections_;
connections_用来保存已经建立的连接,key为nextConnId_,value为TcpConnection的指针。具体操作为:

acceptor_->setNewConnectionCallback(
		std::bind(&TcpServer::newConnection, this,
			std::placeholders::_1, std::placeholders::_2)
	);
在构造函数里,将TcpServer的newConnection成员函数bind到Acceptor的newConnectionCallback_上,用于回调。newConnection函数新建一个TcpConnection对象,并将其加入connections_,并设置相应回调:连接到来回调,消息到来回调,连接关闭回调。这里调来调去,读者可能会头晕,下一小节讲完TcpConnection后,会进行专门梳理。
void TcpServer::newConnection(int sockfd, const InetAddress &peerAddr)
{
	loop_->assertInLoopThread();
	char buff[32];
	snprintf(buff, sizeof buff, "#%d", nextConnId_);
	++nextConnId_;
	std::string connName = name_ + buff;
	std::cout << "TcpServer::newConnection [" << name_ << "] - new connection ["
		<< connName << "] from " << peerAddr.toHostPort() << "\n";
	InetAddress localAddr(basic::getLocalAddr(sockfd));

	TcpConnectionPtr conn(
		new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr)
	);
	connections_[connName] = conn;
	conn->setConnectionCallback(connectionCallback_);
	conn->setMessageCallback(messageCallback_);
	conn->setCloseCallback(
		std::bind(&TcpServer::removeConnection,this,std::placeholders::_1)
	);
	conn->connectEstablished();
}

OK ,,,,over,下一小节讲解最难最多的TcpConnection类







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值