a daytime server use epoll lt mode
here is the code
#include <unistd.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <string>
#include <sys/wait.h>
#include <iostream>
#include <syslog.h>
#include <signal.h>
using std::cout;
using std::endl;
bool stopflag = false;
void handlesignal(int signum)
{
if(signum==SIGTERM)
{
stopflag = true;
}
}
int setnonblocking(int fd)
{
int old_option = fcntl(fd,F_GETFL);
int new_option = old_option|O_NONBLOCK;
fcntl(fd,F_SETFL,new_option);
return old_option;
}
void addtoepoll(int epfd,int fd)
{
setnonblocking(fd);
epoll_event event;
event.events = EPOLLIN;
event.data.fd = fd;
epoll_ctl(epfd,EPOLL_CTL_ADD,fd,&event);
}
std::string getdatestring()
{
int p[2];
pipe(p);
int ret;
if((ret=fork())==0)
{
close(STDOUT_FILENO);
dup(p[1]);
execl("/usr/bin/date","date",nullptr);
exit(-1);
}
else
{
waitpid(ret,nullptr,0);
char buf[500];
int l = read(p[0],buf,500);
return std::string(buf,l);
}
}
void set_reuse_addr(int fd)
{
int option = 1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&option,sizeof(option));
}
int main()
{
daemon(0,0);
signal(SIGTERM,handlesignal);
openlog("my_daytime_server",LOG_PID,LOG_USER);
setlogmask(LOG_UPTO(LOG_DEBUG));
int listen_tcp_fd = socket(AF_INET,SOCK_STREAM,0);
int listen_udp_fd = socket(AF_INET,SOCK_DGRAM,0);
set_reuse_addr(listen_tcp_fd);
set_reuse_addr(listen_udp_fd);
if(listen_tcp_fd<0||listen_udp_fd<0)
{
perror("create socket failed");
return -1;
}
sockaddr_in local_addr;
local_addr.sin_port = htons(13);
local_addr.sin_family=AF_INET;
inet_aton("0.0.0.0",&local_addr.sin_addr);
int ret = bind(listen_tcp_fd,(sockaddr*)&local_addr,sizeof(local_addr));
if(ret<0)
{
perror("bind tcp socket failed");
return -1;
}
ret = bind(listen_udp_fd,(sockaddr*)&local_addr,sizeof(local_addr));
if(ret<0)
{
perror("bind udp socket failed");
return -1;
}
listen(listen_tcp_fd,5);
int epollfd = epoll_create(1);
addtoepoll(epollfd,listen_tcp_fd);
addtoepoll(epollfd,listen_udp_fd);
epoll_event events[20];
while(!stopflag)
{
ret = epoll_wait(epollfd,events,20,-1);
for(int i=0;i<ret;i++)
{
int fd = events[i].data.fd;
sockaddr_in client_addr;
socklen_t length = sizeof(client_addr);
std::string s = getdatestring();
if(fd==listen_tcp_fd)
{
int client_fd = accept(fd,(sockaddr*)&client_addr,&length);
syslog(LOG_USER|LOG_INFO,"recv tcp connection from %s:%d",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
send(client_fd,s.c_str(),s.length(),0);
close(client_fd);
}
else if(fd==listen_udp_fd)
{
char buffer[1024];
recvfrom(listen_udp_fd,buffer,1024,0,(sockaddr*)&client_addr,&length);
syslog(LOG_USER|LOG_INFO,"recv udp package from %s:%d",inet_ntoa(client_addr.sin_addr),ntohs(client_addr.sin_port));
sendto(listen_udp_fd,s.c_str(),s.length(),0,(sockaddr*)&client_addr,length);
}
}
}
closelog();
syslog(LOG_USER|LOG_INFO,"server exit normally by sigterm signal");
return 0;
}
since i'm not familar with the behavior of accept function under et mode, so i choose lt mode.