InetAddress.h | InetAddress.cpp |
#ifndef __INETADDRESS_H__
#define __INETADDRESS_H__
#include<iostream>
#include<netinet/in.h>
using namespace std;
namespace meihao
{
class InetAddress
{
public:
InetAddress(unsigned short port);
InetAddress(const string& ip,unsigned short port);
InetAddress(struct sockaddr_in addr);
const struct sockaddr_in* getInetAddressPtr();
string ip()const;
unsigned short port()const;
private:
struct sockaddr_in _addr;
};
};
#endif
|
#include"InetAddress.h"
#include<iostream>
#include<strings.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
using namespace std;
namespace meihao
{
InetAddress::InetAddress(unsigned short port)
{
bzero(&_addr,sizeof(_addr));
_addr.sin_family = AF_INET;
_addr.sin_port = htons(port);
_addr.sin_addr.s_addr = INADDR_ANY;
}
InetAddress::InetAddress(const string& ip,unsigned short port)
{
bzero(&_addr,sizeof(_addr));
_addr.sin_family = AF_INET;
_addr.sin_port = htons(port);
_addr.sin_addr.s_addr = inet_addr(ip.c_str());
}
InetAddress::InetAddress(struct sockaddr_in addr)
{
_addr = addr;
}
const struct sockaddr_in* InetAddress::getInetAddressPtr()
{
return &_addr;
}
string InetAddress::ip()const
{
return string( inet_ntoa(_addr.sin_addr) );
}
unsigned short InetAddress::port()const
{
return ntohs(_addr.sin_port);
}
};
|
Socket.h | Socket.cpp |
#ifndef __SOCKET_H__
#define __SOCKET_H__
#include<iostream>
#include"InetAddress.h"
using namespace std;
namespace meihao
{
class Socket
{
public:
Socket();
Socket(int fd);
void ready(const InetAddress& addr);
int accept();
void shutdownWrite();
int fd();
static InetAddress getLocalAddress(int fd);
static InetAddress getPeerAddress(int fd);
private:
void setReuseAddr(bool on);
void setReusePort(bool on);
void bind(const InetAddress& addr);
void listen();
private:
int _fd;
};
};
#endif
|
#include"Socket.h"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<strings.h>
using namespace std;
#define handle_error(msg) \
do{\
perror(msg);\
exit(-1);\
}while(0);
namespace meihao
{
int getSocketfd()
{
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(-1==sfd)
{
handle_error("socket");
}
}
Socket::Socket():_fd(getSocketfd())
{
}
Socket::Socket(int fd):_fd(fd)
{
}
void Socket::setReuseAddr(bool on)
{
int val = on?1:0;
int ret = setsockopt(_fd,SOL_SOCKET,SO_REUSEADDR,(const void*)&val,sizeof(int));
if(-1==ret)
{
handle_error("setsockopt");
}
}
void Socket::setReusePort(bool on)
{
int val = on?1:0;
int ret = setsockopt(_fd,SOL_SOCKET,SO_REUSEPORT,(const void *)&val,sizeof(int));
if(-1==ret)
{
handle_error("setsockopt");
}
}
void Socket::bind(const InetAddress& addr)
{
int ret = ::bind(_fd,(const struct sockaddr*)&addr,(socklen_t)sizeof(addr));
if(-1==ret)
{
handle_error("::bind");
}
}
void Socket::listen()
{
int ret = ::listen(_fd,10);
if(-1==ret)
{
handle_error("::listen");
}
}
void Socket::ready(const InetAddress& addr)
{
setReuseAddr(true);
setReusePort(true);
bind(addr);
listen();
}
int Socket::accept()
{
int new_fd = ::accept(_fd,NULL,NULL);
if(-1==new_fd)
{
handle_error("::accept");
}
}
void Socket::shutdownWrite()
{
int ret = ::shutdown(_fd,SHUT_WR);
if(-1==ret)
{
handle_error("::shutdown");
}
}
int Socket::fd()
{
return _fd;
}
InetAddress Socket::getLocalAddress(int fd)
{
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
int addrlen = sizeof(addr);
int ret = ::getsockname(fd,(struct sockaddr*)&addr,(socklen_t*)&addrlen);
if(-1==ret)
{
handle_error("::getsockname");
}
return InetAddress(addr);
}
InetAddress Socket::getPeerAddress(int fd)
{
struct sockaddr_in addr;
bzero(&addr,sizeof(addr));
int addrlen = sizeof(addr);
int ret = ::getpeername(fd,(struct sockaddr*)&addr,(socklen_t*)&addrlen);
if(-1==ret)
{
handle_error("::getpeername");
}
return InetAddress(addr);
}
};
|
SocketIO.h | SocketIO.cpp |
#ifndef __SOCKETIO_H__
#define __SOCKETIO_H__
#include<iostream>
using namespace std;
namespace meihao
{
class SocketIO
{
public:
SocketIO(int fd);
int readn(char* buf,int count);
int writen(const char* buf,int count);
int readline(char* buf,int maxlen); // 成功返回读取字节数,失败返回-1
private:
int recvPeek(char* buf,int count); // 预读取一行
private:
int _fd;
};
};
#endif
|
#include"SocketIO.h"
#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
using namespace std;
namespace meihao
{
SocketIO::SocketIO(int fd):_fd(fd)
{
}
int SocketIO::readn(char* buf,int count)
{
int left = count;
char* ptmp = buf;
while(left>0)
{
int nread = ::recv(_fd,ptmp,left,0);
if(-1==nread)
{
if(errno==EINTR)
continue;
exit(EXIT_FAILURE);
}
else if(0==nread)
break;
left -= nread;
ptmp += nread;
}
return count-left; // 返回发送的数据个数
}
int SocketIO::writen(const char* buf,int count)
{
int left = count;
const char* ptmp = buf;
while(left>0)
{
int nread = ::send(_fd,ptmp,left,0);
if(-1==nread)
{
if(errno==EINTR)
continue;
exit(EXIT_FAILURE);
}
else if(0==nread)
break;
left -= nread;
ptmp += nread;
}
return count-left;
}
int SocketIO::recvPeek(char* buf,int count)
{
int nread = ::recv(_fd,buf,count,MSG_PEEK);
if(-1==nread)
{
perror("recvPeek");
}
}
int SocketIO::readline(char* buf,int maxlen) // 失败返回-1
{
int left = maxlen;
char* ptmp = buf;
int nread = 0;
while(left>0)
{
nread = recvPeek(ptmp,left);
if(-1==nread)
{
if(errno==EINTR)
continue;
return -1;
}
else if(0==nread)
return -1;
for(int idx=0;idx<nread;idx++)
{
if(ptmp[idx]=='\n')
{
if(readn(ptmp,nread)!=nread)
return -1;
left -= nread;
return maxlen-left;
}
}
// 预读取一行没有读到换行
if(readn(ptmp,nread)!=nread)
return -1;
ptmp += nread;
left -= nread;
}
return maxlen-left;
}
};
|
TcpConnection.h | TcpConnection.cpp |
#ifndef __TCPCONNECTION_H__
#define __TCPCONNECTION_H__
#include<iostream>
#include"SocketIO.h"
#include"Socket.h"
#include"InetAddress.h"
#include<memory>
using namespace std;
namespace meihao
{
class TcpConnection;
typedef std::shared_ptr<TcpConnection> TcpConnectionPtr;
//利用智能共享指针托管TcpConnection类型指针,这样不用考虑最后的资源释放
typedef function<void(const TcpConnectionPtr& conn)> TcpConnectionCallback; // 这里要为public,不然后面的Epoll类访问不到,最开始我放到类里面了,放到外面访问更方便
//function函数对象绑定回调函数
class TcpConnection:public std::enable_shared_from_this<TcpConnection>
{
//继承enable_shared_from_this,使用里面的shared_from_this()方法传递指向函数
//本身的指针,防止出现shared_ptr误用造成多次释放或者拷贝
public:
TcpConnection(int confd); // 连接到的fd
~TcpConnection();
string receive();
void send(const string& msg);
void shutdown();
string toString(); // 输出服务器端信息和连接上的客户端的信息
void setConnectionCallback(TcpConnectionCallback cb);
void setMessageCallback(TcpConnectionCallback cb);
void setCloseCallback(TcpConnectionCallback cb);
void handleConnectionCallback(); // 客户端连接上后做出的操作
void handleMessageCallback(); // 服务器端-客户端之间发送消息
void handleCloseCallback(); // 服务器端关闭连接做出的行为
private:
Socket _sock;
SocketIO _sockIO;
InetAddress _localAddress;
InetAddress _peerAddress;
bool _isShutdownWrite;
TcpConnectionCallback _onConnectionCb; // 请求连接到服务器做出的行为
TcpConnectionCallback _onMessageCb; // 双方发送消息
TcpConnectionCallback _onCloseCb; // 关闭链接行为
};
};
#endif
|
#include"TcpConnection.h"
#include<iostream>
#include<strings.h>
#include<stdlib.h>
#include<sstream>
#include<errno.h>
#define handle_error(msg) \
do{\
perror(msg);\
exit(-1);\
}while(0);
using namespace std;
namespace meihao
{
TcpConnection::TcpConnection(int confd):_sock(confd)
,_sockIO(confd)
,_localAddress(meihao::Socket::getLocalAddress(confd))
,_peerAddress(meihao::Socket::getPeerAddress(confd))
,_isShutdownWrite(false)
{
//剩下的回调函数使用成员函数来设置,方便使用过程中修改
}
TcpConnection::~TcpConnection()
{
}
string TcpConnection::receive()
{
char buf[1024];
bzero(buf,sizeof(buf));
int ret = _sockIO.readline(buf,sizeof(buf));
if(-1==ret)
{
handle_error("recvive");
}
return string(buf);
}
void TcpConnection::send(const string& msg)
{
_sockIO.writen(msg.c_str(),msg.size());
}
void TcpConnection::shutdown()
{
if(!_isShutdownWrite) // 没有关闭
{
_isShutdownWrite = true;
_sock.shutdownWrite();
}
}
string TcpConnection::toString()
{
ostringstream oss;
oss<<_localAddress.ip()<<" "<<_localAddress.port()<<"--->"
<<_peerAddress.ip()<<" "<<_peerAddress.port()<<endl;
return oss.str();
}
// 开始初始化类里面的回调函数的值
void TcpConnection::setConnectionCallback(TcpConnectionCallback cb)
{
_onConnectionCb = cb;
}
void TcpConnection::setMessageCallback(TcpConnectionCallback cb)
{
_onMessageCb = cb;
}
void TcpConnection::setCloseCallback(TcpConnectionCallback cb)
{
_onCloseCb = cb;
}
void TcpConnection::handleConnectionCallback()
{
if(_onConnectionCb)
{
_onConnectionCb(shared_from_this()); // 传调用该函数的指针本身
// 等价于 shared_ptr<TcpConnection>(this);
}
}
void TcpConnection::handleMessageCallback()
{
if(_onMessageCb)
{
_onMessageCb(shared_from_this());
}
}
void TcpConnection::handleCloseCallback()
{
if(_onCloseCb)
{
_onCloseCb(shared_from_this());
}
}
};
|
Epoll.h | Epoll.cpp |
#ifndef __EPOLL_H__
#define __EPOLL_H__
#include<iostream>
#include"TcpConnection.h"
#include<vector>
#include<sys/epoll.h>
#include<map>
using namespace std;
namespace meihao
{
class Epoll
{
public:
Epoll(int sfd);
void loop();
void unloop();
void waitEpollfd();
//在epoll类中用函数设置TcpConnection类中的私有变量
void epollSetConnectionCallback(TcpConnectionCallback cb);
void epollSetMessageCallback(TcpConnectionCallback cb);
void epollSetCloseCallback(TcpConnectionCallback cb);
private:
void handleConnection(); //epoll处理新连接的客户端
void handleMessage(int connfd); //处理消息
bool isConnected(int connfd); //查看描述符是否断开
private:
int _efd; // epoll_create得到的fd
int _sfd; // sockfd,用来监听客户端请求
bool _isLooping; // 是否还在监听客户端请求
vector<struct epoll_event> _events; //存放epoll_wait返回的监听描述符事件数组
map<int,TcpConnectionPtr> _mapConnections; // 存放所有客户端请求的描述符和对应的智能指针
TcpConnectionCallback _onConnectionCb; // 为监听到的客户端设置连接的回调函数
TcpConnectionCallback _onMessageCb;
TcpConnectionCallback _onCloseCb;
};
};
#endif
|
#include"Epoll.h"
#include<iostream>
#include<errno.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/epoll.h>
using namespace std;
#define handle_error(msg)\
do{\
perror(msg);\
exit(EXIT_FAILURE);\
}while(0);
namespace meihao
{
int createEpollfd()
{
int efd = ::epoll_create(1); //参数不为0即可
if(-1==efd)
{
handle_error("epoll_create");
}
return efd;
}
void addEpollfd(int efd,int fd)
{
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = fd;
int ret = epoll_ctl(efd,EPOLL_CTL_ADD,fd,&event);
if(-1==ret)
{
handle_error("epoll_ctl");
}
}
void delEpollfd(int efd,int fd)
{
struct epoll_event event;
event.events = EPOLLIN;
event.data.fd = fd;
int ret = epoll_ctl(efd,EPOLL_CTL_DEL,fd,&event);
if(-1==ret)
{
handle_error("epoll_ctl_del");
}
}
Epoll::Epoll(int sfd):_efd(createEpollfd())
,_sfd(sfd)
,_isLooping(false)
,_events(1024) // 容器提前开辟空间
{
addEpollfd(_efd,_sfd);
}
void Epoll::loop() // 开启监听客户端连接请求
{
_isLooping = true;
while(_isLooping)
{
waitEpollfd();
}
}
void Epoll::unloop() //关闭epoll监听
{
if(_isLooping)
_isLooping = false;
}
void Epoll::waitEpollfd()
{
int ret;
do
{
ret = ::epoll_wait(_efd,&(*_events.begin()),_events.size(),5000);
// 事件满足的fd会放到vector里面
}while(-1==ret&&errno==EINTR); // 被中断打断
if(-1==ret)
{
handle_error("epoll_wait");
}
else if(0==ret) // 5S后超时返回
{
cout<<"Epoll wait timeout!"<<endl;
}
for(int idx=0;idx!=ret;++idx)
{
if(_events[idx].data.fd ==_sfd &&_events[idx].events == EPOLLIN)
{//处理新连接
handleConnection();
}
else if(_events[idx].events == EPOLLIN)
{//处理已经连接上的客户端的输入请求
handleMessage(_events[idx].data.fd);
}
}
}
void Epoll::handleConnection()
{
int connfd = ::accept(_sfd,NULL,NULL);
addEpollfd(_efd,connfd);
//处理新的TCP链接
TcpConnectionPtr con(new TcpConnection(connfd));
cout<<"TcpConnectionPtr"<<con<<endl;
//设置TcpConnectionPtr的回调函数
con->setConnectionCallback(_onConnectionCb);
con->setMessageCallback(_onMessageCb);
con->setCloseCallback(_onCloseCb);
_mapConnections.insert(::make_pair(connfd,con)); //map中插入新连接的请求
con->handleConnectionCallback();
}
void Epoll::handleMessage(int connfd)
{
auto it = _mapConnections.find(connfd); //找到map中存放的对应描述符的关键字
if(it!=_mapConnections.end()) //如果描述符确实存在
{
bool flag = isConnected(connfd);
if(flag)
{//链接没有断开
it->second->handleMessageCallback(); //tcp连接处理消息,调用的是TcpConnection类里的函数
}
else
{//断开
delEpollfd(_efd,connfd);
it->second->handleCloseCallback(); //打印显示断开信息
_mapConnections.erase(it); //map中删除对应的pair
}
}
}
bool Epoll::isConnected(int connfd)
{
int ret;
char buf[512];
do
{
ret = recv(connfd,buf,sizeof(buf),MSG_PEEK); //从内核缓冲区预读取
}while(-1==ret&&errno==EINTR);
return ret>0; //>0表示有数据可读,链接没有断开
}
void Epoll::epollSetConnectionCallback(TcpConnectionCallback cb)
{
_onConnectionCb = cb;
}
void Epoll::epollSetMessageCallback(TcpConnectionCallback cb)
{
_onMessageCb = cb;
}
void Epoll::epollSetCloseCallback(TcpConnectionCallback cb)
{
_onCloseCb = cb;
}
};
|
TcpServer.h | TcpServer.cpp |
#ifndef __TCPSERVER_H__
#define __TCPSERVER_H__
#include<iostream>
#include"InetAddress.h"
#include"Socket.h"
#include"Epoll.h"
#include"TcpConnection.h"
using namespace std;
namespace meihao
{
class TcpServer
{
public:
TcpServer(unsigned short port);
TcpServer(const string& ip,unsigned short port);
TcpServer(const InetAddress& addr);
void start();
void stop();
void tcpServerSetConnectionCallback(TcpConnectionCallback cb);
void tcpServerSetMessageCallback(TcpConnectionCallback cb);
void tcpServerSetCloseCallback(TcpConnectionCallback cb);
private:
InetAddress _addr;
Socket _serverSock;
Epoll _epoll;
TcpConnectionCallback _onConnectionCb;
TcpConnectionCallback _onMessageCb;
TcpConnectionCallback _onCloseCb;
};
};
#endif
|
#include"TcpServer.h"
#include<iostream>
using namespace std;
namespace meihao
{
TcpServer::TcpServer(unsigned short port):_addr(port)
,_serverSock()
,_epoll(_serverSock.fd())
{
}
TcpServer::TcpServer(const string& ip,unsigned short port):_addr(ip,port)
,_serverSock()
,_epoll(_serverSock.fd())
{
}
TcpServer::TcpServer(const InetAddress& addr):_addr(addr)
,_serverSock()
,_epoll(_serverSock.fd())
{
}
void TcpServer::start()
{
_serverSock.ready(_addr); // 开启服务器,并监听
//epoll类设置请求的tcp连接的回调函数
_epoll.epollSetConnectionCallback(_onConnectionCb);
_epoll.epollSetMessageCallback(_onMessageCb);
_epoll.epollSetCloseCallback(_onCloseCb);
_epoll.loop(); // epoll_wait客户端连接请求
}
void TcpServer::stop()
{
_epoll.unloop();
_serverSock.shutdownWrite();
}
void TcpServer::tcpServerSetConnectionCallback(TcpConnectionCallback cb)
{
_onConnectionCb = cb;
}
void TcpServer::tcpServerSetMessageCallback(TcpConnectionCallback cb)
{
_onMessageCb = cb;
}
void TcpServer::tcpServerSetCloseCallback(TcpConnectionCallback cb)
{
_onCloseCb = cb;
}
};
|
server.cpp | Makefile |
#include<iostream>
#include"TcpServer.h"
#include"TcpConnection.h"
using namespace std;
void onConnection(const meihao::TcpConnectionPtr& conn)
{
cout<<conn->toString()<<"has connected!"<<endl;
conn->send("connect success!\n");
}
void onMessage(const meihao::TcpConnectionPtr& conn)
{
string msg = conn->receive();
cout<<"recv:"<<msg;
conn->send(msg);
}
void onClosed(const meihao::TcpConnectionPtr& conn)
{
cout<<conn->toString()<<"has closed!"<<endl;
}
int main()
{
meihao::TcpServer tcpServer(8848);
tcpServer.tcpServerSetConnectionCallback(onConnection);
tcpServer.tcpServerSetMessageCallback(onMessage);
tcpServer.tcpServerSetCloseCallback(onClosed);
tcpServer.start();
}
|
OBJS:=*.cpp
ELF:=server
$(ELF):$(OBJS)
g++ $(OBJS) -o $(ELF) -std=c++11
.PHONY:rebuild clean
rebuild:
make clean $(ELF)
clean:
rm -rf $(ELF)
|
client.cpp |
#include<iostream>
#include"InetAddress.h"
#include"SocketIO.h"
#include<strings.h>
#include<unistd.h>
using namespace std;
int main()
{
meihao::InetAddress inetAddr(8848);
int sfd = socket(AF_INET,SOCK_STREAM,0);
if(-1==sfd)
{
perror("socket");
exit(EXIT_FAILURE);
}
int ret = connect(sfd,(const struct sockaddr*)inetAddr.getInetAddressPtr(),sizeof(struct sockaddr));
if(-1==ret)
{
perror("connect");
exit(EXIT_FAILURE);
}
meihao::SocketIO socketIO(sfd);
char buf[1024] = "";
socketIO.readline(buf,sizeof(buf));
cout<<buf;
while(1)
{
bzero(buf,sizeof(buf));
read(0,buf,sizeof(buf));
socketIO.writen(buf,sizeof(buf));
bzero(buf,sizeof(buf));
socketIO.readline(buf,sizeof(buf));
cout<<"recv from server:"<<buf;
}
}
|