直接上代码:
#include <sys/socket.h> #include <sys/wait.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <sys/epoll.h> #include <sys/sendfile.h> #include <sys/stat.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <fcntl.h> #include <errno.h> #define MAX_EVENTS 200 #define PORT 8000 typedef struct { int fd; bool canread; bool canwrite; bool closeFlag; } TcpConn; // 设置socket连接为非阻塞模式 void setnonblocking(int sockfd) { int opts; opts = fcntl(sockfd, F_GETFL); if (opts < 0) { perror("fcntl(F_GETFL)\n"); exit(1); } opts = (opts | O_NONBLOCK); if (fcntl(sockfd, F_SETFL, opts) < 0) { perror("fcntl(F_SETFL)\n"); exit(1); } } void closeConnection(int epfd,TcpConn *conn) { printf("connection closed.\n"); epoll_ctl(epfd, EPOLL_CTL_DEL, conn->fd, NULL); close(conn->fd); free(conn); } int writeData(TcpConn *conn,char *buf,int len) { int nwrite, ptr = 0; while (len > 0) { nwrite = write(conn->fd, buf + ptr, len); if (nwrite < len) { if (nwrite == -1 && errno != EAGAIN) { conn->closeFlag = true; break; } if (nwrite == -1 && errno == EAGAIN) { conn->canwrite = false; break; } } len -= nwrite; ptr += nwrite; } return ptr; } int readData(TcpConn *conn,char *buf,int bufSize) { int nread, ptr = 0; while ((nread = read(conn->fd, buf, bufSize - 1 - ptr)) > 0) { ptr += nread; } if (nread == -1 && errno == EAGAIN) { conn->canread = false; } if (nread==0) { conn->closeFlag = true; } if (nread == -1 && errno != EAGAIN) { conn->closeFlag = true; } return ptr; } int main() { struct epoll_event ev, events[MAX_EVENTS]; int addrlen, listenfd, conn_sock, nfds, epfd, fd, i; struct sockaddr_in local, remote; char buf[BUFSIZ]; // 创建listen socket if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { perror("sockfd\n"); exit(1); } setnonblocking(listenfd); bzero(&local, sizeof(local)); local.sin_family = AF_INET; local.sin_addr.s_addr = htonl(INADDR_ANY); ; local.sin_port = htons(PORT); if (bind(listenfd, (struct sockaddr*)&local, sizeof(local)) < 0) { perror("bind\n"); exit(1); } listen(listenfd, MAX_EVENTS); epfd = epoll_create(MAX_EVENTS); if (epfd == -1) { perror("epoll_create"); exit(EXIT_FAILURE); } TcpConn* listener = (TcpConn*)malloc(sizeof(TcpConn)); listener->fd = listenfd; ev.events = EPOLLIN; ev.data.ptr = listener; if (epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) { perror("epoll_ctl: listen_sock"); exit(EXIT_FAILURE); } for (; ;) { nfds = epoll_wait(epfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_pwait"); exit(EXIT_FAILURE); } for (i = 0; i < nfds; ++i) { TcpConn* conn = (TcpConn*)events[i].data.ptr; fd = conn->fd; if (fd == listenfd) { while ((conn_sock = accept(listenfd, (struct sockaddr*)&remote, (socklen_t*)&addrlen)) > 0) { setnonblocking(conn_sock); // 接收缓冲区 int nRecvBuf=2*1024; // 设置为2K setsockopt (conn_sock,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int)); // 发送缓冲区 int nSendBuf=2*1024; // 设置为2K setsockopt (conn_sock,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int)); TcpConn* newConn = (TcpConn*)malloc(sizeof(TcpConn)); // printf("new conn: %p, socket: %d\n",newConn,conn_sock); if (newConn==NULL) { perror("out of memory."); exit(EXIT_FAILURE); } newConn->fd = conn_sock; newConn->canread = false; newConn->canwrite = false; newConn->closeFlag = false; ev.events = EPOLLIN | EPOLLOUT | EPOLLET; ev.data.ptr = newConn; if (epoll_ctl(epfd, EPOLL_CTL_ADD, conn_sock, &ev)== -1) { perror("epoll_ctl: add"); exit(EXIT_FAILURE); } } if (conn_sock == -1) { if (errno != EAGAIN && errno != ECONNABORTED && errno != EPROTO && errno != EINTR) perror("accept"); } continue; } if (events[i].events & EPOLLIN) { conn->canread = true; int len = readData(conn,buf,BUFSIZ); if (conn->closeFlag) { closeConnection(epfd,conn); continue; } if (len&&(conn->canwrite)) { buf[len] = 0x00; printf("send: %s",buf); writeData(conn,buf,len); if (conn->closeFlag) { closeConnection(epfd,conn); continue; } } } if (events[i].events & EPOLLOUT) { conn->canwrite = true; } } } return 0; }