main.cpp
#include "pollServer.hpp"
#include <memory>
using namespace std;
using namespace poll_ns;
std::string handle(const std::string& request){
return request;
}
static void usage(string proc){
cerr<<proc<<" need a port!!!!"<<endl;
}
int main(int argc,char* argv[]){
if(argc!=2){
usage(argv[0]);
exit(1);
}
uint16_t port=atoi(argv[1]);
unique_ptr<pollServer> svr(new pollServer(handle,port));
svr->init();
svr->start();
return 0;
}
pollServer.hpp
#pragma once
#include <iostream>
#include "sock.hpp"
#include "public.hpp"
#include <errno.h>
#include <cstring>
#include <sys/select.h>
#include <functional>
#include <poll.h>
using namespace std;
namespace poll_ns{
class pollServer{
private:
static const uint16_t defaultPort=8080;
static const int num=2048;
static const int defaultfd=-1;
using func_t=std::function<std::string(const std::string)>;
public:
void print(){
cout<<"socket list:"<<endl;
for(int i=0;i<num;++i){
if(_rfds[i].fd!=defaultfd)cout<<_rfds[i].fd<<" ";
}
cout<<endl;
}
pollServer(func_t func,uint16_t port=defaultPort)
:_func(func),_port(port),_listenSockfd(-1),_rfds(nullptr){}
void init(){
_listenSockfd=Sock::Socket();
Sock::Bind(_listenSockfd,_port);
Sock::Listen(_listenSockfd);
_rfds=new struct pollfd[num];
for(int i=0;i<num;++i){
resetItem(i);
}
_rfds[0].fd=_listenSockfd;
_rfds[0].events=POLLIN;
}
void accepter(){
string clientIp;
uint16_t clientPort;
int sockfd=Sock::Accept(_listenSockfd,&clientIp,&clientPort);
if(sockfd==-1)return;
log(NORMAL,"accept a new link from %s-%d,sockfd=%d",clientIp.c_str(),clientPort,sockfd);
int i=0;
for(;i<num;++i){
if(_rfds[i].fd==defaultfd)break;
}
if(i==num){
log(WARNING,"fdarray is full!!! need close fd");
close(sockfd);
}
else{
_rfds[i].fd=sockfd;
_rfds[i].events=POLLIN;
_rfds[i].revents=0;
}
print();
}
void resetItem(int i){
_rfds[i].fd=defaultfd;
_rfds[i].events=0;
_rfds[i].revents=0;
}
void recver(int pos){
char buffer[1024];
ssize_t n=recv(_rfds[pos].fd,buffer,sizeof(buffer)-1,0);
if(n>0){
buffer[n]=0;
std::cout<<"read a meassge:"<<buffer<<std::endl;
}
else if(n==0){
close(_rfds[pos].fd);
resetItem(pos);
std::cout<<"client close sockfd!!!"<<std::endl;
}
else{
close(_rfds[pos].fd);
resetItem(pos);
std::cerr<<"recv error"<<std::endl;
}
std::string response= _func(buffer);
write(_rfds[pos].fd,response.c_str(),response.size());
}
void handlerReadevents(){
if(_rfds[0].revents&POLLIN)accepter();
for(int i=1;i<num;++i){
if(_rfds[i].fd==defaultfd)continue;
if(!(_rfds[i].events&POLLIN))continue;
if(_rfds[i].revents&POLLIN)recver(i);
}
}
void start(){
int timeout=-1;
while(true){
int n=poll(_rfds,num,timeout);
switch(n){
case 0:
cout<<"poll timeout"<<endl;
log(NORMAL,"poll timeout");
break;
case -1:
log(ERROR,"poll error,errno=%d,strerror=%s",errno,strerror(errno));
break;
default:
handlerReadevents();
break;
}
sleep(1);
}
}
~pollServer(){
if(_listenSockfd>0)close(_listenSockfd);
delete[] _rfds;
}
private:
int _listenSockfd;
uint16_t _port;
struct pollfd* _rfds;
func_t _func;
};
}
sock.hpp
#pragma oncce
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <strings.h>
#include <unistd.h>
#include <sys/wait.h>
#include "Log.hpp"
#include "public.hpp"
using namespace std;
class Sock{
static const int backlog=5;
public:
static int Socket(){
int sockfd=socket(AF_INET,SOCK_STREAM,0);
if(sockfd==-1){
log(ERROR,"create a socket error");
exit(SOCKET_ERR);
}
else log(NORMAL,"create socket success, sockfd=%d",sockfd);
int opt=1;
setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt));
return sockfd;
}
static void Bind(int sockfd,uint16_t port){
struct sockaddr_in local;
socklen_t len=sizeof(local);
bzero(&local,len);
local.sin_family=AF_INET;
local.sin_addr.s_addr=INADDR_ANY;
local.sin_port=htons(port);
int n=bind(sockfd,(const struct sockaddr*)&local,len);
if(n==-1){
log(ERROR,"bind sockfd error");
exit(BIND_ERR);
}
else log(NORMAL,"bind sockfd success");
}
static void Listen(int sockfd){
int n=listen(sockfd,backlog);
if(n==-1){
log(ERROR,"listen sockfd error");
exit(BIND_ERR);
}
else log(NORMAL,"listen sockfd success");
}
static int Accept(int listenSockfd,string* clientIp,uint16_t* clientPort){
struct sockaddr_in client;
socklen_t len=sizeof(client);
bzero(&client,len);
int sockfd=accept(listenSockfd,(struct sockaddr*)&client,&len);
if(sockfd==-1)log(ERROR,"accept sockfd error");
else {
log(NORMAL,"accept a link socket=%d",sockfd);
*clientIp=inet_ntoa(client.sin_addr);
*clientPort=ntohs(client.sin_port);
}
return sockfd;
}
};
Log.hpp
#pragma once
#include <iostream>
#include <time.h>
#include <stdarg.h>
#include <cstdio>
#define NORMAL 0
#define DEBUG 1
#define WARNING 2
#define ERROR 3
#define FATAL 4
using namespace std;
class LogMessage{
private:
string log_path="./log.txt";
string err_path="./err.txt";
static string getLevel(int level){
switch(level){
case NORMAL:
return "NORMAL";
break;
case DEBUG:
return "DEBUG";
break;
case WARNING:
return "WARNING";
break;
case ERROR:
return "ERROR";
break;
case FATAL:
return "FATAL";
break;
default:
return "OTHER";
}
}
string getTime(){
time_t now=time(nullptr);
struct tm* t=localtime(&now);
int year=t->tm_year+1900;
int mon=t->tm_mon+1;
int day=t->tm_mday;
int hour=t->tm_hour;
int min=t->tm_min;
int sec=t->tm_sec;
char buffer[64];
sprintf(buffer,"%d-%02d-%02d %02d:%02d:%02d",year,mon,day,hour,min,sec);
return buffer;
}
public:
void operator()(int level,const char* format,...){
string lev=getLevel(level);
string time=getTime();
va_list list;
va_start(list,format);
char msg[1024];
vsnprintf(msg,sizeof(msg),format,list);
FILE* log=fopen(log_path.c_str(),"a+");
FILE* err=fopen(err_path.c_str(),"a+");
if(log!=nullptr&&err!=nullptr){
FILE* cur=nullptr;
if(level==NORMAL||level==DEBUG){
cur=log;
}
else cur=err;
fprintf(cur,"[%s][%s][%s]\n",lev.c_str(),time.c_str(),msg);
fclose(log);
fclose(err);
}
}
};
static LogMessage log;
public.hpp
#pragma once
#include <iostream>
enum{SOCKET_ERR=1,BIND_ERR,LISTEN_ERR,ACCEPT_ERR,USAGE_ERR};