-
Acceptor用于accept(2)接受TCP连接
-
Acceptor的数据成员包括Socket、Channel,Acceptor的socket是listening socket(即server socket)。Channel用于观察此socket的readable事件,并回调Accptor::handleRead(),后者调用accept(2)来接受新连接,并回调用户callback。
Acceptor的头文件
Acceptor.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 an internal header file, you should not include this.
#ifndef MUDUO_NET_ACCEPTOR_H
#define MUDUO_NET_ACCEPTOR_H
#include <boost/function.hpp>
#include <boost/noncopyable.hpp>
#include <muduo/net/Channel.h>
#include <muduo/net/Socket.h>
namespace muduo
{
namespace net
{
class EventLoop;
class InetAddress;
///
/// Acceptor of incoming TCP connections.
///
class Acceptor : boost::noncopyable
{
public:
typedef boost::function<void (int sockfd,
const InetAddress&)> NewConnectionCallback;
Acceptor(EventLoop* loop, const InetAddress& listenAddr);
~Acceptor();
void setNewConnectionCallback(const NewConnectionCallback& cb)
{ newConnectionCallback_ = cb; }
bool listenning() const { return listenning_; }
void listen();
private:
/*这是监听套接字的可读事件的套接字*/
void handleRead();
EventLoop* loop_;
Socket acceptSocket_; /*监听套接字*/
;/*通道 会观察acceptSocket_监听套接字的可读事件,这个channel所属的eventloop是loop_*/
Channel acceptChannel_;
NewConnectionCallback newConnectionCallback_;
/*是否处于监听的状态*/
bool listenning_;
int idleFd_;
};
}
}
#endif // MUDUO_NET_ACCEPTOR_HAcceptor源文件
Acceptor.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/Acceptor.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/SocketsOps.h>
#include <boost/bind.hpp>
#include <errno.h>
#include <fcntl.h>
//#include <sys/types.h>
//#include <sys/stat.h>
using namespace muduo;
using namespace muduo::net;
Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr)
: loop_(loop),
/*创建一个监听套接字*/
acceptSocket_(sockets::createNonblockingOrDie()),
/*acceptchannel 关注acceptSocket_套接字的事件 */
acceptChannel_(loop, acceptSocket_.fd()),
listenning_(false),
/*预先准备一个文件描述符*/
idleFd_(::open("/dev/null", O_RDONLY | O_CLOEXEC))
{
assert(idleFd_ >= 0);
/*设置地址重复利用*/
acceptSocket_.setReuseAddr(true);
/*绑定地址*/
acceptSocket_.bindAddress(listenAddr);
/*设置监听套接字“读”的套接字*/
acceptChannel_.setReadCallback(
boost::bind(&Acceptor::handleRead, this));
}
/*虚构函数*/
Acceptor::~Acceptor()
{
/*先取消 acceptSocket_的所有事件,然后才移除*/
acceptChannel_.disableAll();
acceptChannel_.remove();
::close(idleFd_);
}
/*监听 监听套接字*/
void Acceptor::listen()
{/*断言在IO线程中*/
loop_->assertInLoopThread();
listenning_ = true;
acceptSocket_.listen();
/*关注acceptSocket_的可读事件*/
acceptChannel_.enableReading();
}
/*监听套接字的可读事件的回调函数*/
void Acceptor::handleRead()
{
/*断言在IO线程中*/
loop_->assertInLoopThread();
/*创建一个对等方的地址,这是客户端的地址*/
InetAddress peerAddr(0);
//FIXME loop until no more
/*对等连接套接字*/
int connfd = acceptSocket_.accept(&peerAddr);
if (connfd >= 0)
{
// string hostport = peerAddr.toIpPort();
// LOG_TRACE << "Accepts of " << hostport;
/*回调上层(应用层)的回调函数*/
if (newConnectionCallback_)
{
newConnectionCallback_(connfd, peerAddr);
}
/*如果应用层没有回调函数,则直接关闭此连接套接字*/
else
{
sockets::close(connfd);
}
}
else
{
// Read the section named "The special problem of
// accept()ing when you can't" in libev's doc.
// By Marc Lehmann, author of livev.
/*如果是文件符超出限制*/
if (errno == EMFILE)
{
/**/
::close(idleFd_);
/*因为这是电平触发,所以为了防止一直触发,可以先接受,然后关闭掉*/
idleFd_ = ::accept(acceptSocket_.fd(), NULL, NULL);
::close(idleFd_);
idleFd_ = ::open("/dev/null", O_RDONLY | O_CLOEXEC);
}
}
}测试程序
#include <muduo/net/Acceptor.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/InetAddress.h>
#include <muduo/net/SocketsOps.h>
#include <stdio.h>
using namespace muduo;
using namespace muduo::net;
void newConnection(int sockfd, const InetAddress& peerAddr)
{
printf("newConnection(): accepted a new connection from %s\n",
peerAddr.toIpPort().c_str());
::write(sockfd, "How are you?\n", 13);
sockets::close(sockfd);
}
int main()
{
printf("main(): pid = %d\n", getpid());
InetAddress listenAddr(8888);
EventLoop loop;
Acceptor acceptor(&loop, listenAddr);
acceptor.setNewConnectionCallback(newConnection);
acceptor.listen();
loop.loop();
}程序输出
ubuntu@ubuntu-virtual-machine:~$ telnet 127.0.0.1 8888
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
How Are You ?
Connection closed by foreign host.
ubuntu@ubuntu-virtual-machine:~$ telnet 127.0.0.1 8888
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
How Are You ?
Connection closed by foreign host.
ubuntu@ubuntu-virtual-machine:~$
本文介绍了Muduo网络库中的Acceptor组件,它用于处理TCP连接请求。Acceptor通过监听特定端口,使用EventLoop和Channel来观察并接受新的连接。文章还提供了一个简单的测试程序示例。
9998

被折叠的 条评论
为什么被折叠?



