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.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注