直接上代码
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/epoll.h>
#include <netinet/in.h>
#include<signal.h>
#define LISTENQ 20 //
#define EPOLLEVENTS 512 //
#define FDSIZE 1024 //
int socket_bind(const char *ip, int port)
{
int listenfd;
struct sockaddr_in servaddr;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if (listenfd == -1)
{
perror("socket error:");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
inet_pton(AF_INET, ip, &servaddr.sin_addr);
servaddr.sin_port = htons(port);
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1)
{
perror("bind error: ");
exit(1);
}
return listenfd;
}
int do_accpet(int epollfd, int listenfd)
{
int clifd,ret;
struct sockaddr_in cliaddr;
socklen_t cliaddrlen=sizeof(struct sockaddr_in);
struct epoll_event ev;
clifd = accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddrlen);
if (clifd == -1)
{
perror("server accpet error");
}
else
{
ev.events = EPOLLIN|EPOLLERR;
ev.data.fd = clifd;
ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, clifd, &ev);
if(ret != 0 )
{
close(clifd);
}
}
return 0;
}
int handle_events(int epollfd, struct epoll_event *events, int num, int listenfd)
{
int i;
int fd;
int ret=0;
uint8_t buf[4096];
int len=0,nread=0;
for (i = 0; i < num; i++)
{
fd = events[i].data.fd;
if ((fd == listenfd) && (events[i].events & EPOLLIN))
{
do_accpet(epollfd, listenfd);
}
else if (events[i].events & EPOLLIN )
{
nread = read(fd, buf, 4096);
if(nread > 0)
{
write(fd, buf,nread);
}
else
{
epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
close(fd);
}
}
else if (events[i].events & EPOLLOUT )
{
}
else if (events[i].events & EPOLLERR)
{
close(events[i].data.fd);
}
else
{
}
}
return ret;
}
int do_epoll(int listenfd)
{
int epollfd;
struct epoll_event events[EPOLLEVENTS];
int ret;
struct epoll_event ev;
epollfd = epoll_create(FDSIZE);
if(epollfd<0)
{
exit(1);
}
ev.events = EPOLLIN;
ev.data.fd = listenfd;
epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev);
for (;;)
{
ret = epoll_wait(epollfd, events, EPOLLEVENTS, 1000);
if(ret < 0)
{
perror("epoll_wait error");
exit(1);
}
else if (ret>0)
{
handle_events(epollfd, events, ret, listenfd);
}
else
{
}
}
close(epollfd);
}
void mydaemon(void)
{
int i;
int fd0;
pid_t pid;
struct sigaction sa;
umask(0);
pid = fork();
if(pid < 0){
perror("fork error!\n");
exit(1);
}else if(pid > 0){
exit(0);
}
setsid(); //创建一个会话
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if(sigaction(SIGCHLD, &sa, NULL) < 0){//注册子进程退出忽略信号
return ;
}
if(chdir("/") < 0){//将当前工作目录更改为根目录
printf("chlid dir error!\n");
return;
}
//关闭不需要的文件描述符,或者重定向到/dev/null
close(0);
fd0 = open("/dev/null", O_RDWR);
dup2(fd0, 1);
dup2(fd0, 2);
}
int main(int argc, char *argv[])
{
int listenfd,fd;
char ip[INET6_ADDRSTRLEN]="127.0.0.1";
int port = 1234;
int ret,opt;
char *optstr = "i:p:";
while((opt = getopt(argc,argv,optstr))!=-1)
{
switch(opt)
{
case 'i':
strcpy(ip,optarg);
break;
case 'p':
port = atoi(optarg);
break;
case '?':
printf("run like: ./echo -i 0.0.0.0 -p 1234\n");
return 0;
break;
}
}
mydaemon();
listenfd = socket_bind(ip, port);
ret = listen(listenfd, LISTENQ);
if(ret != 0)
{
perror("listen error: ");
exit(1);
}
printf("listen on %s,%d\n",ip,port);
do_epoll(listenfd);
return 0;
}