#include <sys/types.h> /* basic system data types */ #include <sys/socket.h> /* basic socket definitions */ #include <sys/time.h> /* timeval{} for select() */ #include <time.h> /* timespec{} for pselect() */ #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ #include <arpa/inet.h> /* inet(3) functions */ #include <errno.h> #include <fcntl.h> /* for nonblocking */ #include <netdb.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> /* for S_xxx file mode constants */ #include <sys/uio.h> /* for iovec{} and readv/writev */ #include <unistd.h> #include <sys/wait.h> #include <sys/un.h> /* for Unix domain sockets */ #include <sys/event.h> #define MAXLINE 4096 #define SERV_PORT 9877 #define SA struct sockaddr #define LISTENQ 1024 #define MAX_CONNECT 1024 ssize_t Writen(int fd, const void *vptr, size_t n); ssize_t readline(int fd, void *vptr, size_t maxlen); static ssize_t my_read(int fd, char *ptr); int main(int argc, char **argv) { int i, maxi, listenfd, connfd, sockfd; int nready, client[MAX_CONNECT]; ssize_t n; char line[MAXLINE]; socklen_t clilen; struct sockaddr_in cliaddr, servaddr; struct kevent ev; struct timespec ts = { 10, 0 }, ts1 = {0,0}; int kq; listenfd = socket(AF_INET, SOCK_STREAM, 0); bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = htonl(INADDR_ANY); servaddr.sin_port = htons(SERV_PORT); bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); listen(listenfd, LISTENQ); maxi = -1; //初始化该队列 kq = kqueue(); //添加第一个需要检测的listenfd //EVFILT_READ和EVFILT_WRITE只用设一个就可以了 EV_SET( &ev, listenfd, EVFILT_READ|EVFILT_WRITE, EV_ADD|EV_ENABLE, 0,0,0); kevent(kq, &ev, 1, NULL, 0, &ts1); for (i = 0; i < MAX_CONNECT; i++) client[i] = -1; /* -1 indicates available entry */ //memset可以不要,只是为了明白以后ev的值是从kevent函数中返回的。 memset(&ev,0,sizeof(struct kevent)); for ( ; ; ) { //等待IO可用 nready = kevent(kq, NULL, 0, &ev, 1, &ts ); if( nready == -1 ) { printf("kevent(2)"); exit(1); } if( nready == 0 ) { printf("TIMEOUT /n"); continue; } if ( nready > 0) { printf("ev: ident = %d, filter = %d, flags = %d, fflags = %d, data = %d, nready = %d/n", ev.ident, ev.filter, ev.flags, ev.fflags, ev.data,nready); if( ev.ident == listenfd) { printf("new connection/n"); clilen = sizeof(cliaddr); connfd = accept(listenfd, (SA *) &cliaddr, &clilen); printf("new client: %s, port %d/n",inet_ntop(AF_INET, &cliaddr.sin_addr, 4, NULL),ntohs(cliaddr.sin_port)); for (i = 0; i < MAX_CONNECT; i++) { if (client[i] < 0) { client[i] = connfd; /* save descriptor */ break; } } if (i == MAX_CONNECT) { printf("too many clients"); exit(1); } printf("add the sockfd info to kqueue/n"); //如果没有下面两句,client的任何输入都不能从服务器回响 //即说明,kevent根本不检查该connfd。 EV_SET( &ev, connfd, EVFILT_READ|EVFILT_WRITE, EV_ADD|EV_ENABLE, 0,0,0); kevent(kq, &ev, 1, NULL, 0, &ts1); if (i > maxi) maxi = i; continue; } for (i = 0; i <= maxi; i++) { /* check all clients for data */ if ( (sockfd = client[i]) < 0) continue; if ( ev.ident == sockfd ) { if ( (n = readline(sockfd, line, MAXLINE)) == 0) { /*4connection closed by client */ close(sockfd); if( sockfd ) { printf("remove the sockfd info from kqueue/n"); EV_SET( &ev, sockfd, EVFILT_READ|EVFILT_WRITE, EV_DELETE, 0,0,0); kevent(kq, &ev, 1, NULL, 0, &ts1); } //FD_CLR(sockfd, &allset); client[i] = -1; } else { Writen(sockfd, line, n); break;/* no more readable descriptors */ } } } } } exit(0); } ssize_t Writen(int fd, const void *vptr, size_t n) { size_t nleft; ssize_t nwritten; const char *ptr; ptr = vptr; nleft = n; while (nleft > 0) { if ( (nwritten = write(fd, ptr, nleft)) <= 0) { if (errno == EINTR) nwritten = 0; /* and call write() again */ else return(-1); /* error */ } nleft -= nwritten; ptr += nwritten; } return(n); } ssize_t readline(int fd, void *vptr, size_t maxlen) { int n, rc; char c, *ptr; ptr = vptr; for (n = 1; n < maxlen; n++) { if ( (rc = my_read(fd, &c)) == 1) { *ptr++ = c; if (c == '/n') break; /* newline is stored, like fgets() */ } else if (rc == 0) { if (n == 1) return(0); /* EOF, no data read */ else break; /* EOF, some data was read */ } else return(-1); /* error, errno set by read() */ } *ptr = 0; /* null terminate like fgets() */ return(n); } static ssize_t my_read(int fd, char *ptr) { static int read_cnt = 0; static char *read_ptr; static char read_buf[MAXLINE]; if (read_cnt <= 0) { again: if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) { if (errno == EINTR) goto again; return(-1); } else if (read_cnt == 0) return(0); read_ptr = read_buf; } read_cnt--; *ptr = *read_ptr++; return(1); }