Acceptor负责accpet一个TCP客户连接并执行相应的回调通知连接的使用者
TcpConnection是指一个TCP连接,执行相应的连接回调
TcpServer管理所有的TCP连接
#include<iostream>
#include<stdio.h>
#include<map>
#include<string>
#include<boost/any.hpp>
#include<boost/enable_shared_from_this.hpp>
#include<boost/noncopyable.hpp>
#include<boost/scoped_ptr.hpp>
#include<boost/shared_ptr.hpp>
#include<netinet/in.h>
#include<errno.h>
#include<fcntl.h>
#include<stdio.h>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<endian.h>
#include<netinet/tcp.h>
#include<netinet/in.h>
#include<boost/noncopyable.hpp>
#include<boost/function.hpp>
#include<boost/static_assert.hpp>
#include<boost/bind.hpp>
#include<string>
#include<stdio.h>
#include<iostream>
#include"EventLoop.hpp"
namespace sockets{
inline uint64_t hostToNetwork64(uint64_t host64)
{//主机字节序转为网络字节序
return htobe64(host64);
}
inline uint32_t hostToNetwork32(uint32_t host32)
{
return htonl(host32);
}
inline uint16_t hostToNetwork16(uint16_t host16)
{
return htons(host16);
}
inline uint64_t networkToHost64(uint64_t net64)
{//网络字节序转为主机字节序
return be64toh(net64);
}
inline uint32_t networkToHost32(uint32_t net32)
{
return ntohl(net32);
}
inline uint16_t networkToHost16(uint16_t net16)
{
return ntohs(net16);
}
typedef struct sockaddr SA;
const SA* sockaddr_cast(const struct sockaddr_in* addr){//强制转换
return static_cast<const SA*>(implicit_cast<const void*>(addr));
}
SA* sockaddr_cast(struct sockaddr_in* addr){
return static_cast<SA*>(implicit_cast<void*>(addr));
}
void setNonBlockAndCloseOnExec(int sockfd){//将描述符设置为非阻塞和O_CLOEXEC(close on exec)
int flags = ::fcntl(sockfd, F_GETFL, 0);
flags |= O_NONBLOCK;
int ret = ::fcntl(sockfd, F_SETFL, flags);
flags = ::fcntl(sockfd, F_GETFD, 0);
flags |= FD_CLOEXEC;
ret = ::fcntl(sockfd, F_SETFD, flags);
}
int createNonblockingOrDie()
{//socket()创建非阻塞的socket描述符
#if VALGRIND
int sockfd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sockfd < 0) {
printf("socket() error\n");
}
setNonBlockAndCloseOnExec(sockfd);
#else
int sockfd = ::socket(AF_INET,
SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
IPPROTO_TCP);
if (sockfd < 0){
printf("socke() error\n");
}
#endif
return sockfd;
}
void bindOrDie(int sockfd, const struct sockaddr_in& addr)
{//bind()
int ret = ::bind(sockfd, sockaddr_cast(&addr), sizeof addr);
if (ret < 0) {
printf("bind() error\n");
}
}
void listenOrDie(int sockfd){//listen()
int ret = ::listen(sockfd, SOMAXCONN);
if (ret < 0){
printf("listen() error\n");
}
}
int accept(int sockfd, struct sockaddr_in* addr)
{//accept()
socklen_t addrlen = sizeof *addr;
#if VALGRIND
int connfd = ::accept(sockfd, sockaddr_cast(addr), &addrlen);
setNonBlockAndCloseOnExec(connfd);
#else
int connfd = ::accept4(sockfd, sockaddr_cast(addr),
&addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC);
#endif
if (connfd < 0){
int savedErrno = errno;
printf("accept error\n");
switch (savedErrno)
{
case EAGAIN:
case ECONNABORTED:
case EINTR:
case EPROTO: // ???
case EPERM:
case EMFILE: // per-process lmit of open file desctiptor ???
errno = savedErrno;
break;
case EBADF:
case EFAULT:
case EINVAL:
case ENFILE:
case ENOBUFS:
case ENOMEM:
case ENOTSOCK:
case EOPNOTSUPP:
printf("accept() fatal erro\n");
break;
default:
printf("accpet() unknown error\n");
break;
}
}
return connfd;
}
void close(int sockfd){//close()
if (::close(sockfd) < 0){
printf("sockets::close\n");
}
}
void toHostPort(char* buf, size_t size,const struct sockaddr_in& addr)
{//将IPv4地址转为IP和端口
char host[INET_ADDRSTRLEN] = "INVALID";
::inet_ntop(AF_INET, &addr.sin_addr, host, sizeof host);
uint16_t port =networkToHost16(addr.sin_port);
snprintf(buf, size, "%s:%u", host, port);
}
void fromHostPort(const char* ip, uint16_t port,struct sockaddr_in* addr)
{//将主机IP和端口转为IPv4地址
addr->sin_family = AF_INET;
addr->sin_port = hostToNetwork16(port);
if (::inet_pton(AF_INET, ip, &addr->sin_addr) <= 0)
{
printf("sockets::fromHostPort\n");
}
}
sockaddr_in getLocalAddr(int sockfd)
{
struct sockaddr_in localaddr;
bzero(&localaddr, sizeof localaddr);
socklen_t addrlen = sizeof(localaddr);
if (::getsockname(sockfd, sockaddr_cast(&localaddr), &addrlen) < 0)
{
printf("getsockname() error\n");
}
return localaddr;
}
}//end-namespace
class InetAddress;
class Socket:noncopyable{//创建一个socket描述符fd并绑定sockaddr,监听fd功能
public:
explicit Socket(int sockfd):sockfd_(sockfd){}
~Socket();
int fd() const{return sockfd_;}
void bindAddress(const InetAddress& addr);
void listen();
int accept(InetAddress* peeraddr);
void setReuseAddr(bool on);
private:
const int sockfd_;
};
class InetAddress{//sockaddr地址的风黄钻
public:
explicit InetAddress(uint16_t port);
InetAddress(const string& ip,uint16_t port);
InetAddress(const struct sockaddr_in& addr):addr_(addr){}
string toHostPort() const;
const struct sockaddr_in& getSockAddrInet() const{return addr_;}
void setSockAddrInet(const struct sockaddr_in& addr){addr_=addr;}
private:
struct sockaddr_in addr_;
};
BOOST_STATIC_ASSERT(sizeof(InetAddress)==sizeof(struct sockaddr_in));//编译时断言
class Acceptor:noncopyable{//接受TCP连接并执行相应的回调
public:
typedef function<void(int sockfd,const InetAddress&)> NewConnectionCallback;
Acceptor(EventLoop* loop,const InetAddress& listenAddr);
void setNewConnectionCallback(const NewConnectionCallback& cb)
{ newConnectionCallback_=cb;}
bool listening() const{return listening_;}
void listen();
private:
void handleRead();
EventLoop* loop_;
Socket acceptSocket_;
Channel acceptChannel_;
NewConnectionCallback newConnectionCallback_;
bool listening_;
};
/*
*Socket实现
*/
Socket::~Socket()
{
sockets::close(sockfd_);
}
void Socket::bindAddress(const InetAddress& addr)
{
sockets::bindOrDie(sockfd_, addr.getSockAddrInet());
}
void Socket::listen()
{
sockets::listenOrDie(sockfd_);
}
int Socket::accept(InetAddress* peeraddr)
{
struct sockaddr_in addr;
bzero(&addr, sizeof addr);
int connfd = sockets::accept(sockfd_, &addr);
if (connfd >= 0)
{
peeraddr->setSockAddrInet(addr);
}
return connfd;
}
void Socket::setReuseAddr(bool on)
{
int optval = on ? 1 : 0;
::setsockopt(sockfd_, SOL_SOCKET, SO_REUSEADDR,
&optval, sizeof optval);
}
/*
*InetAddress实现
*/
static const in_addr_t kInaddrAny=INADDR_ANY;//任意的网络字节序IP地址为0
InetAddress::InetAddress(uint16_t port)
{
bzero(&addr_, sizeof addr_);
addr_.sin_family = AF_INET;
addr_.sin_addr.s_addr = sockets::hostToNetwork32(kInaddrAny);
addr_.sin_port = sockets::hostToNetwork16(port);
}
InetAddress::InetAddress(const std::string& ip, uint16_t port)
{
bzero(&addr_, sizeof addr_);
sockets::fromHostPort(ip.c_str(), port, &addr_);
}
string InetAddress::toHostPort() const
{
char buf[32];
sockets::toHostPort(buf, sizeof buf, addr_);
return buf;
}
/*
*Acceptor实现
*/
Acceptor::Acceptor(EventLoop* loop, const InetAddress& listenAddr)
: loop_(loop),
acceptSocket_(sockets::createNonblockingOrDie()),
acceptChannel_(loop, acceptSocket_.fd()),
listening_(false)
{
acceptSocket_.setReuseAddr(true);
acceptSocket_.bindAddress(listenAddr);
acceptChannel_.setReadCallBack(
boost::bind(&Acceptor::handleRead, this));
}
void Acceptor::listen()
{
loop_->assertInLoopThread();
listening_ = true;
acceptSocket_.listen();
acceptChannel_.enableReading();
}
void Acceptor::handleRead()
{
loop_->assertInLoopThread();
InetAddress peerAddr(0);
int connfd = acceptSocket_.accept(&peerAddr);
if (connfd >= 0) {
if (newConnectionCallback_) {
newConnectionCallback_(connfd, peerAddr);
} else {
sockets::close(connfd);
}
}
}
/*
*测试代码
*/
/*
void newConnection(int sockfd, const InetAddress& peerAddr)
{
printf("newConnection(): accepted a new connection from %s\n",
peerAddr.toHostPort().c_str());
::write(sockfd, "How are you?\n", 13);
sockets::close(sockfd);
}
int main()
{
printf("main(): pid = %d\n", getpid());
InetAddress listenAddr(9981);
EventLoop loop;
Acceptor acceptor(&loop, listenAddr);
acceptor.setNewConnectionCallback(newConnection);
acceptor.listen();
InetAddress listenAddr1(12345);
Acceptor acceptor1(&loop,listenAddr1);
acceptor1.setNewConnectionCallback(newConnection);
acceptor1.listen();
loop.loop();
}
*/
using namespace std;
using namespace boost;
class TcpConnection;//表示一个TCP连接
typedef shared_ptr<TcpConnection> TcpConnectionPtr;//
/*
*TcpConnection
*/
class TcpConnection:noncopyable,public enable_shared_from_this<TcpConnection>{
public:
typedef function<void(const TcpConnectionPtr&)> ConnectionCallback;//连接建立回调函数
typedef function<void(const TcpConnectionPtr&,const char* data,ssize_t len)> MessagCallback;//消息回调函数
TcpConnection(EventLoop* loop,const string& name,int sockfd,
const InetAddress& localAddr,const InetAddress& peerAddr);
~TcpConnection();
EventLoop* getLoop() const{return loop_;}
const string& name() const{return name_;}
const InetAddress& localAddr(){return localAddr_;}
const InetAddress& peerAddress(){return peerAddr_;}
bool connected() const{return state_==kConnected;}
void setConnectionCallback(const ConnectionCallback& cb){
connectionCallback_=cb;
}
void setMessageCallback(const MessagCallback& cb){
messageCallback_=cb;
}
void connectEstablished();
private:
enum StateE{kConnecting,kConnected,};
void setState(StateE s){state_=s;}
void handleRead();
EventLoop* loop_;
string name_;
StateE state_;
scoped_ptr<Socket> socket_;
scoped_ptr<Channel> channel_;
InetAddress localAddr_;
InetAddress peerAddr_;
ConnectionCallback connectionCallback_;
MessagCallback messageCallback_;
};
/*
*Tcpserver
*/
class TcpServer:noncopyable{//管理所有的TCP连接
public:
typedef function<void()> ConnectionCallback;
typedef function<void()> MessagCallback;
TcpServer(EventLoop* loop,const InetAddress& listenAddr);
~TcpServer();
void start();
void setConnectionCallback(const ConnectionCallback& cb){
connectionCallback_=cb;
}
void setMessageCallback(const MessagCallback& cb){
messageCallback_=cb;
}
private:
void newConnection(int sockfd,const InetAddress& peerAddr);
typedef map<string,TcpConnectionPtr> ConnectionMap;
EventLoop* loop_;
const string name_;
scoped_ptr<Acceptor> acceptor_;
ConnectionCallback connectionCallback_;
MessagCallback messageCallback_;
bool started_;
int nextConnId_;
ConnectionMap connections_;
};
/*
*TcpConnection实现
*/
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)
{
channel_->setReadCallBack(
boost::bind(&TcpConnection::handleRead, this));
}
TcpConnection::~TcpConnection()
{
printf("TcpConnection::%s,fd=%d\n",name_.c_str(),channel_->fd());
}
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);
}
/*
*TcpServer实现
*/
TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr)
: loop_(loop),
name_(listenAddr.toHostPort()),
acceptor_(new Acceptor(loop, listenAddr)),
started_(false),
nextConnId_(1)
{
acceptor_->setNewConnectionCallback(
boost::bind(&TcpServer::newConnection, this, _1, _2));
}
TcpServer::~TcpServer()
{
}
void TcpServer::start()
{
if (!started_)
{
started_ = true;
}
if (!acceptor_->listening())
{
loop_->runInLoop(
boost::bind(&Acceptor::listen, get_pointer(acceptor_)));
}//通过EventLoop监听服务端的listenfd
}
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{//用于Acceptor接受一个连接后通过此回调通知使用者
loop_->assertInLoopThread();
char buf[32];
snprintf(buf, sizeof buf, "#%d", nextConnId_);
++nextConnId_;
string connName = name_ + buf;
InetAddress localAddr(sockets::getLocalAddr(sockfd));
TcpConnectionPtr conn(
new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr));
connections_[connName]=conn;
conn->setConnectionCallback(connectionCallback_);//传递给TcpConnection
conn->setMessageCallback(messageCallback_);
conn->connectEstablished();//调用ConnectionCallback
}
/*
*测试代码
*/
void onConnection(const TcpConnectionPtr& conn)
{
if (conn->connected())
{
printf("onConnection(): new connection [%s] from %s\n",
conn->name().c_str(),
conn->peerAddress().toHostPort().c_str());
}
else
{
printf("onConnection(): connection [%s] is down\n",
conn->name().c_str());
}
}
void onMessage(const :TcpConnectionPtr& conn,
const char* data,
ssize_t len)
{
printf("onMessage(): received %zd bytes from connection [%s]\n",
len, conn->name().c_str());
}
int main()
{
printf("main(): pid = %d\n", getpid());
InetAddress listenAddr(9981);
EventLoop loop;
TcpServer server(&loop, listenAddr);
server.setConnectionCallback(onConnection);
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}