一.在客户端登录服务器,建立长连接,请求服务时,通常服务器端要检查客户端是否还保持连接,若连接已经断开,则服务器不再向该客户端提供服务,
这种ping服务器的机制通常称为心跳,若在一定时间内没收到ping信息,则说明客户端已经断线。如下图,就是模拟实现了在高并发连接中处理ping信息时,
服务器端收到的ping请求,如图:
说明:由上图可以看出,有3个客户端不断地向服务器发送ping心跳信息,uri为5表示ping请求,uri为3表示登录,当然这些都是人为规定的,
上述言简意赅地叙述了本文字的主题,下面接着讲服务器端如何实现。
二.服务器相关初始化:
1.创建epoll相关文件描述符监听读写事件,如下:
HighConcurrentServer::HighConcurrentServer() {
if ((epfd = epoll_create(MAXEVENTS)) == -1) {
exit(-1);
}
if ((connfd = epoll_create(MAXEVENTS)) == -1) {
exit(-1);
}
}
2.IP地址,端口的绑定,以及socket的创建,如下:
void HighConcurrentServer::initServerAddr(){
std::string localAddr = "your server ip address";
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = ::inet_addr(localAddr.c_str());
serverAddr.sin_port = htons(SERV_PORT);
}
void HighConcurrentServer::createSocket(){
listenfd = socket(AF_INET, SOCK_STREAM, 0);
setnonblocking(listenfd);//设置非阻塞,实现很简单,这里略去
evt.data.fd = listenfd;
evt.events = EPOLLIN | EPOLLET;
epoll_ctl(connfd, EPOLL_CTL_ADD, listenfd, &evt);
bind(listenfd, (sockaddr *)&serverAddr, sizeof(serverAddr));
listen(listenfd, MAX_CONNECTOR);
}
3.监听客户端的连接,如下:
void HighConcurrentServer::connectHandle(){
int n = -1;
n = epoll_wait(connfd, events, MAXEVENTS, 0);
int sockfd = 0;
socklen_t clilen;
for(int i=0;i
if(events[i].data.fd == listenfd){
sockfd = accept(listenfd, (sockaddr *)&clientAddr, &clilen);
setnonblocking(sockfd);
char *str = inet_ntoa(clientAddr.sin_addr);
printf("[HighConcurrentServer::connectHandle] clientAddr:%s, sockfd:%d, addrLength:%d\n", str, sockfd, clilen);//打印输出客户端的ip地址
ClientSession *client = new ClientSession(sockfd);//为每个客户端的连接创建一个ClientSession对象,由该对象实现数据的收发
evSet.insert((Poco::UInt64)(client->epevent.data.ptr));
epAdd(client);//表示连接成功后,用epfd监听该对象相关的sockfd
}
}
}
4.与客户端有关的数据的收发,如下:
void HighConcurrentServer::readHandle(){
int n = -1;
n = epoll_wait(epfd, events, MAXEVENTS, 0);
int sockfd = 0;
socklen_t clilen;
for(int i=0;i
//先要检查发生事件的对象的指针是否为空,这里略去
ClientSession* client = (ClientSession*)((EpollEvent*)(events[i].data.ptr))->conn;
if(events[i].events & (EPOLLERR | EPOLLHUP)){
printf("[HighConcurrentServer::readHandle] epoll recv err:socket close\n");
client->close();
continue;
}
if (events[i].events & EPOLLIN) {
#ifdef OPEN_LOG
printf("[HighConcurrentServer::readHandle] EPOLLIN event happen\n");
#endif
client->recvData();
}
/*
if(events[i].events & EPOLLOUT){
printf("[HighConcurrentServer::readHandle] EPOLLOUT event happen\n");
client->writable = true;
}else{
client->writable = false;
}
*/
}
}
void HighConcurrentServer::writeHandle(){
int n = -1;
n = epoll_wait(epfd, events, MAXEVENTS, 0);
int sockfd = 0;
socklen_t clilen;
for(int i=0;i
//先要检查发生事件的对象是否为空,这里略去
ClientSession* client = (ClientSession*)((EpollEvent*)(events[i].data.ptr))->conn;
if(events[i].events & (EPOLLERR | EPOLLHUP)){
printf("[HighConcurrentServer::writeHandle] epoll recv err:socket close\n");
client->close();
continue;
}
if (events[i].events & EPOLLOUT) {
#ifdef OPEN_LOG
printf("[HighConcurrentServer::writedHandle] EPOLLOUT event happen\n");
#endif
}
}
}
5.服务的实现,如下:
void HighConcurrentServer::service() {
connectHandle();
readHandle();
writeHandle();
}
~未完待续
转载请注明出处:山水间博客,http://blog.csdn.net/linyanwen99/article/details/8315779