/* do_accept: establish the new connection * @listenfd: the listening fd * @epollfd: the epollfd used to monitor the listening fd and new connected fd * * */ void do_accept(int listenfd, int epollfd) { int connfd; struct sockaddr_in clitaddr; socklen_t socklen; //while ( (connfd = accept(listenfd,(struct sockaddr *)&clitaddr,&socklen)) > 0 ) //{ connfd = accept(listenfd,(struct sockaddr *)&clitaddr,&socklen); /* show client info */ show_peer_info(connfd); /* set the connfd to non-block socket */ //setnonblock(connfd); /* set the connfd events to EPOLLIN | EPLLET(edge trigger) */ //int state = EPOLLIN | EPOLLET; int state = EPOLLIN; /* add connected fd to epoll set */ add_epoll_event(epollfd,connfd,state); //} /* if accept error*/ if (connfd < 0) { if (errno != EINTR) { perror_exit("accept error"); } } }
/* handle_connection: handle the connected clients * @listenfd: the socket used to accept connections * * */ void handle_connection(int listenfd) { /* the number of readable fds in the pollfd array */ int nready, i; /* receive buffer */ buffer_t recvbuf; memset(&recvbuf,0,sizeof(buffer_t)); /* set the listenfd to non-block */ //setnonblock(listenfd); /* epollfd set to monitor the related events */ int epollfd; if ( (epollfd = epoll_create(EPOLL_SIZE)) < 0 ) { perror_exit("epoll create error"); } /* epoll event array */ struct epoll_event events[EPOLL_EVENTS]; /* add the listen socket to epoll set */ int state = EPOLLIN; add_epoll_event(epollfd,listenfd,state); while( 1 ) { /* obtain the ready sockets from the epoll set */ if ( (nready = epoll_wait(epollfd,events,EPOLL_EVENTS,INFTIM)) < 0) { perror_exit("epoll wait error"); } /* traverse the ready sockets */ for (i = 0; i < nready; ++i) { int fd = events[i].data.fd; /* listenfd is ready */ if ( fd == listenfd && (events[i].events & EPOLLIN) ) { do_accept(listenfd, epollfd); } /* connected sockets are ready */ else if ( events[i].events & EPOLLIN ) { do_read(fd,epollfd,&recvbuf); } /* read the data from the connected socket and echo it also */ else if ( events[i].events & EPOLLOUT ) { do_write(fd,epollfd,&recvbuf); } } } }
void run_client(int port) { int epfd; int connfd; int rc; struct sockaddr_in addr; epfd = epoll_create(10); connfd = socket(AF_INET, SOCK_STREAM, 0); setnonblock(connfd); memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); inet_aton("127.0.0.1", &addr.sin_addr); rc = connect(connfd, (struct sockaddr*) &addr, sizeof(addr)); if (rc < 0 && errno == EINPROGRESS) printf("connecting...\n"); else if (rc == 0) printf("connected to server.\n"); else { perror("connect"); } add_epoll_event(epfd, connfd, EPOLLIN | EPOLLOUT); for ( ; ; ) { struct epoll_event events[32]; int count = epoll_wait(epfd, events, 32, -1); int i; printf("%d events\n", count); for (i = 0; i < count; ++i) { int error; int rc; socklen_t len = sizeof(int); if (events[i].events & EPOLLOUT) { rc = getsockopt(events[i].data.fd, SOL_SOCKET, SO_ERROR, &error, &len); if (rc < 0) perror("getsockopt"); if (error == 0) { printf("EPOLLOUT\n"); } else { fprintf(stderr, "could not connect to server: %s\n", strerror(error)); } write(events[i].data.fd, "hi", 2); } if (events[i].events & EPOLLIN) { rc = getsockopt(events[i].data.fd, SOL_SOCKET, SO_ERROR, &error, &len); if (rc < 0) perror("getsockopt"); printf("EPOLLIN\n"); } if (events[i].events & EPOLLERR) { printf("EPOLLERR\n"); } } } }
/* client handle the info received from both server and standard input * @connfd: the connected socket used for communication * */ void client_info(int connfd) { int i; int shutdown_flag = 0; /* recv and send buffer */ buffer_t recvbuf, sendbuf; memset(&recvbuf,0,sizeof(buffer_t)); memset(&sendbuf,0,sizeof(buffer_t)); //setnonblock(connfd); /* epollfd set monitors conncted socket fd and standard input, if either one is * readable, then we obtain the info from it*/ int epollfd, fd; if ( (epollfd = epoll_create(EPOLL_SIZE)) < 0 ) { perror_exit("epoll create error"); } struct epoll_event events[4]; int nready; add_epoll_event(epollfd,STDIN_FILENO,EPOLLIN); while( 1 ) { if ( (nready = epoll_wait(epollfd,events,4,INFTIM)) < 0 ) { perror("epollfd error"); } for (i = 0; i < nready; ++i) { fd = events[i].data.fd; if (fd == STDIN_FILENO && (events[i].events & EPOLLIN) ) { int space = buffer_hasspace(&sendbuf); if (space > 0) { int nread = read(fd,&sendbuf.buffer[sendbuf.in],space); /* read error */ if (nread < 0) { if (errno != EINTR) { perror_exit("read error"); } } else if (nread == 0) { /* read "ctrl+d" from client, close the connection and delete the event from epoll set */ shutdown_flag = 1; shutdown(connfd,SHUT_WR); delete_epoll_event(epollfd,fd, EPOLLIN); } else { sendbuf.in += nread; /* add connection fd to epoll set */ add_epoll_event(epollfd,connfd,EPOLLOUT); } } } if (fd == connfd && (events[i].events & EPOLLOUT) ) { int ntotal = strlen(sendbuf.buffer); int nwrite = write(fd,&sendbuf.buffer[sendbuf.out],ntotal); if (nwrite < 0) { perror_exit("write error"); } else { sendbuf.out += ntotal; /* all data has benn sent out, reset the buffer space */ if (sendbuf.in == sendbuf.out) { buffer_reset(&sendbuf); } /* modify the fd from epoll set to EPOLLIN since all data has been sent out */ modify_epoll_event(epollfd,fd,EPOLLIN); } } if (fd == connfd && (events[i].events & EPOLLIN) ) { int space = buffer_hasspace(&recvbuf); if (space > 0) { int nread = read(fd,&recvbuf.buffer[recvbuf.in],space); /* read error */ if (nread < 0) { perror_exit("read error"); } /* read "FIN" from server */ else if (nread == 0) { /* we have sent "FIN" already */ if (shutdown_flag == 0) { printf("server terminates unexpectedly!\n"); exit(EXIT_FAILURE); } else return; } else { recvbuf.in += nread; /* add STDOUT_FILENO to epoll set */ delete_epoll_event(epollfd,connfd,EPOLLIN); add_epoll_event(epollfd,STDOUT_FILENO,EPOLLOUT); } } } if (fd == STDOUT_FILENO && (events[i].events & EPOLLOUT) ) { int ntotal = strlen(recvbuf.buffer); int nwrite = write(fd,&recvbuf.buffer[recvbuf.out],ntotal); if (nwrite < 0) { if (errno != EAGAIN) { perror_exit("write error"); } } else { recvbuf.out += ntotal; /* all data has been sent to STANDARD OUTPUT, reset * the buffer space */ if (recvbuf.in == recvbuf.out) { buffer_reset(&recvbuf); delete_epoll_event(epollfd,STDOUT_FILENO,EPOLLOUT); } } } } } }