Linux网络通信编程(套接字模型TCP\UDP与IO多路复用模型select\poll\epoll)
Linux下测试代码:
http://www.linuxhowtos.org/C_C++/socket.htm
TCP模型
1 //TCPClient.c 2 #include<string.h> 3 #include<netinet/in.h> 4 #include<sys/types.h> 5 #include<sys/socket.h> 6 #include<errno.h> 7 #define MYPORT 4000 8 #define BACKLOG 10 9 #define MAX_LEN 100 10 11 int main(void) 12 { 13 int sockfd; 14 int tmp_int; 15 char *msg_send = NULL; 16 char *msg_recv = NULL; 17 int sin_size; 18 int len,bytes_sent,bytes_recv; 19 struct sockaddr_in my_addr; 20 struct sockaddr_in dest_addr; 21 22 sockfd=socket(AF_INET,SOCK_STREAM,0); 23 my_addr.sin_family=AF_INET; 24 my_addr.sin_port=htons(MYPORT); 25 my_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); 26 bzero(&(my_addr.sin_zero),8); 27 tmp_int = connect(sockfd,(struct sockaddr*)(&my_addr),sizeof(struct sockaddr)); 28 if( tmp_int < 0 ) 29 { 30 printf("ERROR:connect erro %s!\n", strerror(errno)); 31 close(sockfd); 32 return -1; 33 } 34 msg_send="This is TCPClient!\n"; 35 len=strlen(msg_send); 36 bytes_sent=send(sockfd,msg_send,len,0); 37 while( len != bytes_sent ) 38 { 39 tmp_int = bytes_sent; 40 len -= bytes_sent; 41 printf("send %d,%d packet!\n", bytes_sent,len); 42 bytes_sent = send( sockfd, msg_send+tmp_int, len, 0 ); 43 } 44 msg_recv = (char *)malloc( MAX_LEN ); 45 if( NULL == msg_recv ) 46 { 47 printf("ERROR:malloc mem error!\n"); 48 close(sockfd); 49 return -1; 50 } 51 memset(msg_recv, 0, MAX_LEN ); 52 bytes_recv=recv(sockfd,msg_recv,MAX_LEN,0); 53 if( bytes_recv >0 ) 54 { 55 printf("recv: %s\n!", msg_recv ); 56 } 57 else 58 { 59 printf("ERROR:net error\n"); 60 } 61 close(sockfd); 62 return 0; 63 }
1 //TCPServer.c 2 #include<string.h> 3 #include<errno.h> 4 #include<netinet/in.h> 5 #include<sys/types.h> 6 #include<sys/socket.h> 7 #define MYPORT 4000 8 #define BACKLOG 10 9 #define MAX_LEN 100 10 11 int main(void) 12 { 13 int sockfd; 14 char* msg_send; 15 char* msg_recv; 16 int sin_size; 17 int new_fd; 18 int tmp_int; 19 int len,bytes_sent,bytes_recv; 20 struct sockaddr_in my_addr; 21 struct sockaddr_in their_addr; 22 23 sockfd=socket(AF_INET,SOCK_STREAM,0); 24 my_addr.sin_family=AF_INET; 25 my_addr.sin_port=htons(MYPORT); 26 my_addr.sin_addr.s_addr=inet_addr("127.0.0.1"); 27 bzero(&(my_addr.sin_zero),8); 28 bind(sockfd,(struct sockaddr*)(&my_addr),sizeof(struct sockaddr)); 29 listen(sockfd,BACKLOG); 30 sin_size=sizeof(struct sockaddr_in); 31 new_fd=accept(sockfd,(struct sockaddr *)&their_addr, &sin_size); 32 msg_send="This is TCPServer!\n"; 33 len=strlen(msg_send); 34 bytes_sent=send(new_fd,msg_send,len,0); 35 while( len != bytes_sent ) 36 { 37 tmp_int = bytes_sent; 38 len -= bytes_sent; 39 printf("send %d packet\n", bytes_sent); 40 bytes_sent = send( new_fd, msg_send+tmp_int, len, 0 ); 41 } 42 msg_recv = (char *)malloc( MAX_LEN ); 43 if( NULL == msg_recv ) 44 { 45 printf("ERROR:malloc mem error!\n"); 46 close(new_fd); 47 return -1; 48 } 49 memset(msg_recv, 0, MAX_LEN ); 50 bytes_recv=recv(new_fd,msg_recv,MAX_LEN,0); 51 if( bytes_recv >0 ) 52 { 53 printf("recv: %s\n", msg_recv ); 54 } 55 else 56 { 57 printf("ERROR:net error!\n"); 58 } 59 close(new_fd); 60 close(sockfd); 61 return 0; 62 }
UDP模型
1 //UDPServer.c 2 #include <stdio.h> 3 #include <sys/types.h> 4 #include <sys/socket.h> 5 #include <netinet/in.h> 6 #include <arpa/inet.h> 7 #include <netdb.h> 8 #include <string.h> 9 #include <unistd.h> 10 #include <stdlib.h> 11 #include <sys/wait.h> 12 #include <sys/stat.h> 13 #include <errno.h> 14 15 #define RET_OK 0 16 #define RET_ERR -1 17 #define LISTEN_QUEUE_NUM 5 18 #define BUFFER_SIZE 256 19 #define ECHO_PORT 2029 20 21 int main(int argc, char **argv) 22 { 23 int sockfd, len, opt = 1; 24 struct sockaddr_in cliaddr; 25 uint8_t buffer[BUFFER_SIZE]; 26 int ret = RET_OK; 27 28 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 29 { 30 perror("ERROR: opening socket!"); 31 return RET_ERR; 32 } 33 if((ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) < 0) 34 { 35 perror("ERROR: set sockopt!"); 36 close(sockfd); 37 return 0; 38 } 39 memset(&cliaddr, 0, sizeof(cliaddr)); 40 cliaddr.sin_family = AF_INET; 41 cliaddr.sin_addr.s_addr = INADDR_ANY; 42 cliaddr.sin_port = htons(ECHO_PORT); 43 if ((ret = bind(sockfd, (struct sockaddr *) &cliaddr, sizeof(cliaddr))) < 0) 44 { 45 perror("ERROR: on binding"); 46 goto failed; 47 } 48 49 do 50 { 51 len = sizeof(cliaddr); 52 if((ret = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr *)&cliaddr, &len)) > 0) 53 { 54 printf("Recv from %s\r\n", inet_ntoa(cliaddr.sin_addr)); 55 ret = sendto(sockfd, buffer, ret, 0, (struct sockaddr *)&cliaddr, len); 56 } 57 }while(ret >= 0); 58 59 close(sockfd); 60 return 0; 61 }
1 //UDPClient.c 2 #include <stdio.h> 3 #include <sys/types.h> 4 #include <sys/socket.h> 5 #include <netinet/in.h> 6 #include <arpa/inet.h> 7 #include <netdb.h> 8 #include <string.h> 9 #include <unistd.h> 10 #include <stdlib.h> 11 #include <sys/wait.h> 12 #include <sys/stat.h> 13 #include <errno.h> 14 15 #define RET_OK 0 16 #define RET_ERR -1 17 #define LISTEN_QUEUE_NUM 5 18 #define BUFFER_SIZE 256 19 #define ECHO_PORT 2029 20 21 int main(int argc, char *argv[]) 22 { 23 int sockfd, ret = RET_OK; 24 struct sockaddr_in servaddr; 25 struct hostent *server; 26 char buffer[BUFFER_SIZE]; 27 28 if (argc < 2) { 29 fprintf(stderr,"ERROR: usage %s hostname\n", argv[0]); 30 return RET_ERR; 31 } 32 if((server = gethostbyname(argv[1])) == NULL) 33 { 34 herror("ERROR: get host by name. "); 35 return RET_ERR; 36 } 37 38 if((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 39 { 40 perror("ERROR: opening socket"); 41 return RET_ERR; 42 } 43 memset(&servaddr, 0, sizeof(servaddr)); 44 servaddr.sin_family = AF_INET; 45 servaddr.sin_addr.s_addr = *(uint32_t *)server->h_addr; 46 servaddr.sin_port = htons((uint16_t)ECHO_PORT); 47 48 while(1) 49 { 50 printf("Enter the message : "); 51 if(fgets(buffer, sizeof(buffer) - 1, stdin) == NULL) 52 { 53 break; 54 } 55 if((ret = sendto(sockfd, buffer ,strlen(buffer), 0, (struct sockaddr *)&servaddr, sizeof(servaddr))) < 0) 56 { 57 perror("ERROR: writing to socket"); 58 break; 59 } 60 if((ret = recvfrom(sockfd, buffer, sizeof(buffer) - 1, 0, NULL, NULL)) < 0) 61 { 62 perror("ERROR: reading from socket"); 63 break; 64 } 65 buffer[ret] = 0; 66 printf("Server echo message: %s\n",buffer); 67 } 68 close(sockfd); 69 return ret < 0 ? RET_ERR : RET_OK; 70 }
1 #Makefile 2 3 PROGRAM_CLIENT = client 4 PROGRAM_SERVER = server 5 6 CC = gcc 7 8 LDPATH = /usr/local/lib 9 10 INCLUDEDIR = . 11 12 SOURCE_PATH = . 13 14 OPTS = -g -Wall -I. -I$(INCLUDEDIR) 15 16 CFLAGS = $(OPTS) -fPIC 17 18 LIBS = -L./ -L$(LDPATH) 19 20 all: $(PROGRAM_SERVER) $(PROGRAM_CLIENT) 21 22 clean: 23 rm -f *.o *.core *.bak $(PROGRAM_CLIENT) $(PROGRAM_SERVER) *.a core.* *.exe 24 25 $(PROGRAM_CLIENT): $(LIBRARY) $(SOURCE_PATH)/client.c 26 $(CC) $(CFLAGS) $(SOURCE_PATH)/client.c $(LIBS) -o $(PROGRAM_CLIENT) $(OBJS) -Wl,-rpath,./ 27 28 $(PROGRAM_SERVER): $(LIBRARY) $(SOURCE_PATH)/server.c 29 $(CC) $(CFLAGS) $(SOURCE_PATH)/server.c $(LIBS) -o $(PROGRAM_SERVER) $(OBJS) -Wl,-rpath,./
select模型
1 //server.c 2 #include <sys/types.h> 3 #include <ctype.h> 4 #include <strings.h> 5 #include <unistd.h> 6 #include <sys/socket.h> 7 #include <netinet/in.h> 8 #include <netdb.h> 9 #include <arpa/inet.h> 10 #include <ctype.h> 11 #include <errno.h> 12 #include <sys/time.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <sys/select.h> 16 #include <stdlib.h> 17 18 #define LISTEN_QUEUE_NUM 5 19 #define BUFFER_SIZE 256 20 #define ECHO_PORT 2029 21 22 int main(int argc, char **argv) 23 { 24 struct sockaddr_in servaddr, remote; 25 int request_sock, new_sock; 26 int nfound, fd, maxfd, bytesread; 27 uint32_t addrlen; 28 fd_set rset, set; 29 struct timeval timeout; 30 char buf[BUFFER_SIZE]; 31 32 if ((request_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { 33 perror("socket"); 34 return -1; 35 } 36 memset(&servaddr, 0, sizeof(servaddr)); 37 servaddr.sin_family = AF_INET; 38 servaddr.sin_addr.s_addr = INADDR_ANY; 39 servaddr.sin_port = htons((uint16_t)ECHO_PORT); 40 41 if (bind(request_sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) 42 { 43 perror("bind"); 44 return -1; 45 } 46 if (listen(request_sock, LISTEN_QUEUE_NUM) < 0) 47 { 48 perror("listen"); 49 return -1; 50 } 51 52 FD_ZERO(&set); 53 FD_SET(request_sock, &set); 54 maxfd = request_sock; 55 while(1) { 56 rset = set; 57 timeout.tv_sec = 0; 58 timeout.tv_usec = 500000; 59 if((nfound = select(maxfd + 1, &rset, (fd_set *)0, (fd_set *)0, &timeout)) < 0) 60 { 61 perror("select"); 62 return -1; 63 } 64 else 65 if (nfound == 0) 66 { 67 printf("."); fflush(stdout); 68 continue; 69 } 70 if (FD_ISSET(request_sock, &rset)) 71 { 72 addrlen = sizeof(remote); 73 if ((new_sock = accept(request_sock, (struct sockaddr *)&remote, &addrlen)) < 0) 74 { 75 perror("accept"); 76 return -1; 77 } 78 printf("connection from host %s, port %d, socket %d\r\n", 79 inet_ntoa(remote.sin_addr), ntohs(remote.sin_port), 80 new_sock); 81 FD_SET(new_sock, &set); 82 if (new_sock > maxfd) 83 maxfd = new_sock; 84 FD_CLR(request_sock, &rset); 85 nfound --; 86 } 87 for (fd=0; fd <= maxfd && nfound > 0; fd++) { 88 if (FD_ISSET(fd, &rset)) { 89 nfound --; 90 if ((bytesread = read(fd, buf, sizeof buf - 1))<0) 91 { 92 perror("read"); 93 } 94 if (bytesread == 0) 95 { 96 fprintf(stderr, "server: end of file on %d\r\n",fd); 97 FD_CLR(fd, &set); 98 close(fd); 99 continue; 100 } 101 buf[bytesread] = 0; 102 printf("%s: %d bytes from %d: %s\n", argv[0], bytesread, fd, buf); 103 if (write(fd, buf, bytesread) < 0) 104 { 105 perror("echo"); 106 FD_CLR(fd, &set); 107 close(fd); 108 } 109 } 110 } 111 } 112 return 0; 113 }
1 //client.c 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <sys/time.h> 5 #include <netinet/in.h> 6 #include <errno.h> 7 #include <ctype.h> 8 #include <netdb.h> 9 #include <stdio.h> 10 #include <string.h> 11 #include <stdlib.h> 12 #include <unistd.h> 13 #include <sys/select.h> 14 15 16 #define RET_OK 0 17 #define RET_ERR -1 18 #define LISTEN_QUEUE_NUM 5 19 #define BUFFER_SIZE 256 20 #define ECHO_PORT 2029 21 22 int main(int argc, char **argv) 23 { 24 int sock, maxfd = 0; 25 struct sockaddr_in servaddr; 26 struct hostent *server; 27 fd_set rset, set; 28 int nfound, bytesread; 29 char buf[BUFFER_SIZE]; 30 31 if (argc < 2) 32 { 33 fprintf(stderr,"usage %s hostname\n", argv[0]); 34 return RET_ERR; 35 } 36 if((server = gethostbyname(argv[1])) == NULL) 37 { 38 herror("gethostbyname. "); 39 return RET_ERR; 40 } 41 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 42 { 43 perror("socket"); 44 return -1; 45 } 46 memset(&servaddr, 0, sizeof(servaddr)); 47 servaddr.sin_family = AF_INET; 48 servaddr.sin_addr.s_addr = *(uint32_t *)server->h_addr; 49 servaddr.sin_port = htons((uint16_t)ECHO_PORT); 50 if (connect(sock, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) 51 { 52 perror("connect"); 53 return -1; 54 } 55 maxfd = fileno(stdin); 56 FD_ZERO(&set); 57 FD_SET(sock, &set); 58 FD_SET(maxfd, &set); 59 maxfd = (maxfd > sock ? maxfd : sock) + 1; 60 while(1) 61 { 62 rset = set; 63 if ((nfound = select(maxfd, &rset, (fd_set *)0, (fd_set *)0, NULL)) < 0) 64 { 65 if (errno == EINTR) { 66 fprintf(stderr, "interrupted system call\n"); 67 continue; 68 } 69 perror("select"); 70 exit(1); 71 } 72 if (FD_ISSET(fileno(stdin), &rset)) { 73 if (fgets(buf, sizeof(buf), stdin) == NULL) { 74 if (ferror(stdin)) { 75 perror("stdin"); 76 return -1; 77 } 78 return 0; 79 } 80 if (write(sock, buf, strlen(buf)) < 0) 81 { 82 perror("write"); 83 return -1; 84 } 85 } 86 if (FD_ISSET(sock,&rset)) { 87 if((bytesread = read(sock, buf, sizeof buf)) < 0) 88 { 89 perror("read"); 90 exit(1); 91 } 92 else 93 if(bytesread == 0) 94 { 95 fprintf(stderr, "server disconnect\n"); 96 exit(0); 97 } 98 buf[bytesread] = 0; 99 printf("%s\n",buf); 100 } 101 } 102 return 0; 103 }
1 #Makefile 2 PROGRAM_CLIENT = client 3 PROGRAM_SERVER = server 4 5 CC = gcc 6 7 LDPATH = /usr/local/lib 8 9 INCLUDEDIR = . 10 11 SOURCE_PATH = . 12 13 OPTS = -g -Wall -I. -I$(INCLUDEDIR) 14 15 CFLAGS = $(OPTS) -fPIC 16 17 LIBS = -L./ -L$(LDPATH) 18 19 all: $(PROGRAM_SERVER) $(PROGRAM_CLIENT) 20 21 clean: 22 rm -f *.o *.core *.bak $(PROGRAM_CLIENT) $(PROGRAM_SERVER) *.a core.* *.exe 23 24 $(PROGRAM_CLIENT): $(LIBRARY) $(SOURCE_PATH)/client.c 25 $(CC) $(CFLAGS) $(SOURCE_PATH)/client.c $(LIBS) -o $(PROGRAM_CLIENT) $(OBJS) -Wl,-rpath,./ 26 27 $(PROGRAM_SERVER): $(LIBRARY) $(SOURCE_PATH)/server.c 28 $(CC) $(CFLAGS) $(SOURCE_PATH)/server.c $(LIBS) -o $(PROGRAM_SERVER) $(OBJS) -Wl,-rpath,./
poll模型
1 //server.c 2 #include <unistd.h> 3 #include <sys/types.h> /* basic system data types */ 4 #include <sys/socket.h> /* basic socket definitions */ 5 #include <netinet/in.h> /* sockaddr_in{} and other Internet defns */ 6 #include <arpa/inet.h> /* inet(3) functions */ 7 8 #include <stdlib.h> 9 #include <errno.h> 10 #include <stdio.h> 11 #include <string.h> 12 13 14 #include <poll.h> /* poll function */ 15 #include <limits.h> 16 17 #define MAXLINE 10240 18 19 #ifndef OPEN_MAX 20 #define OPEN_MAX 40960 21 #endif 22 23 void handle(struct pollfd* clients, int maxClient, int readyClient); 24 25 int main(int argc, char **argv) 26 { 27 int servPort = 6888; 28 int listenq = 1024; 29 int listenfd, connfd; 30 struct pollfd clients[OPEN_MAX]; 31 int maxi; 32 socklen_t socklen = sizeof(struct sockaddr_in); 33 struct sockaddr_in cliaddr, servaddr; 34 char buf[MAXLINE]; 35 int nready; 36 37 bzero(&servaddr, socklen); 38 servaddr.sin_family = AF_INET; 39 servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 40 servaddr.sin_port = htons(servPort); 41 42 listenfd = socket(AF_INET, SOCK_STREAM, 0); 43 if (listenfd < 0) { 44 perror("socket error"); 45 } 46 47 int opt = 1; 48 if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) { 49 perror("setsockopt error"); 50 } 51 52 if(bind(listenfd, (struct sockaddr *) &servaddr, socklen) == -1) { 53 perror("bind error"); 54 exit(-1); 55 } 56 if (listen(listenfd, listenq) < 0) { 57 perror("listen error"); 58 } 59 60 clients[0].fd = listenfd; 61 clients[0].events = POLLIN; 62 int i; 63 for (i = 1; i< OPEN_MAX; i++) 64 clients[i].fd = -1; 65 maxi = listenfd + 1; 66 67 printf("pollechoserver startup, listen on port:%d\n", servPort); 68 printf("max connection is %d\n", OPEN_MAX); 69 70 for ( ; ; ) { 71 nready = poll(clients, maxi + 1, -1); 72 //printf("nready is %d\n", nready); 73 if (nready == -1) { 74 perror("poll error"); 75 } 76 if (clients[0].revents & POLLIN) { 77 connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &socklen); 78 sprintf(buf, "accept form %s:%d\n", inet_ntoa(cliaddr.sin_addr), cliaddr.sin_port); 79 printf(buf, ""); 80 81 for (i = 0; i < OPEN_MAX; i++) { 82 if (clients[i].fd == -1) { 83 clients[i].fd = connfd; 84 clients[i].events = POLLIN; 85 break; 86 } 87 } 88 89 if (i == OPEN_MAX) { 90 fprintf(stderr, "too many connection, more than %d\n", OPEN_MAX); 91 close(connfd); 92 continue; 93 } 94 95 if (i > maxi) 96 maxi = i; 97 98 --nready; 99 } 100 101 handle(clients, maxi, nready); 102 } 103 } 104 105 void handle(struct pollfd* clients, int maxClient, int nready) { 106 int connfd; 107 int i, nread; 108 char buf[MAXLINE]; 109 110 if (nready == 0) 111 return; 112 113 for (i = 1; i< maxClient; i++) { 114 connfd = clients[i].fd; 115 if (connfd == -1) 116 continue; 117 if (clients[i].revents & (POLLIN | POLLERR)) { 118 nread = read(connfd, buf, MAXLINE);//读取客户端socket流 119 if (nread < 0) { 120 perror("read error"); 121 close(connfd); 122 clients[i].fd = -1; 123 continue; 124 } 125 if (nread == 0) { 126 printf("client close the connection"); 127 close(connfd); 128 clients[i].fd = -1; 129 continue; 130 } 131 132 write(connfd, buf, nread);//响应客户端 133 if (--nready <= 0)//没有连接需要处理,退出循环 134 break; 135 } 136 } 137 }
epoll模型
1 #include <sys/socket.h> 2 #include <sys/epoll.h> 3 #include <netinet/in.h> 4 #include <arpa/inet.h> 5 #include <fcntl.h> 6 #include <unistd.h> 7 #include <stdio.h> 8 #include <errno.h> 9 #include <iostream> 10 using namespace std; 11 #define MAX_EVENTS 500 12 struct myevent_s 13 { 14 int fd; 15 void (*call_back)(int fd, int events, void *arg); 16 int events; 17 void *arg; 18 int status; // 1: in epoll wait list, 0 not in 19 char buff[128]; // recv data buffer 20 int len; 21 long last_active; // last active time 22 }; 23 // set event 24 void EventSet(myevent_s *ev, int fd, void (*call_back)(int, int, void*), void *arg) 25 { 26 ev->fd = fd; 27 ev->call_back = call_back; 28 ev->events = 0; 29 ev->arg = arg; 30 ev->status = 0; 31 ev->last_active = time(NULL); 32 } 33 // add/mod an event to epoll 34 void EventAdd(int epollFd, int events, myevent_s *ev) 35 { 36 struct epoll_event epv = {0, {0}}; 37 int op; 38 epv.data.ptr = ev; 39 epv.events = ev->events = events; 40 if(ev->status == 1){ 41 op = EPOLL_CTL_MOD; 42 } 43 else{ 44 op = EPOLL_CTL_ADD; 45 ev->status = 1; 46 } 47 if(epoll_ctl(epollFd, op, ev->fd, &epv) < 0) 48 printf("Event Add failed[fd=%d]\n", ev->fd); 49 else 50 printf("Event Add OK[fd=%d]\n", ev->fd); 51 } 52 // delete an event from epoll 53 void EventDel(int epollFd, myevent_s *ev) 54 { 55 struct epoll_event epv = {0, {0}}; 56 if(ev->status != 1) return; 57 epv.data.ptr = ev; 58 ev->status = 0; 59 epoll_ctl(epollFd, EPOLL_CTL_DEL, ev->fd, &epv); 60 } 61 int g_epollFd; 62 myevent_s g_Events[MAX_EVENTS+1]; // g_Events[MAX_EVENTS] is used by listen fd 63 void RecvData(int fd, int events, void *arg); 64 void SendData(int fd, int events, void *arg); 65 // accept new connections from clients 66 void AcceptConn(int fd, int events, void *arg) 67 { 68 struct sockaddr_in sin; 69 socklen_t len = sizeof(struct sockaddr_in); 70 int nfd, i; 71 // accept 72 if((nfd = accept(fd, (struct sockaddr*)&sin, &len)) == -1) 73 { 74 if(errno != EAGAIN && errno != EINTR) 75 { 76 printf("%s: bad accept", __func__); 77 } 78 return; 79 } 80 do 81 { 82 for(i = 0; i < MAX_EVENTS; i++) 83 { 84 if(g_Events[i].status == 0) 85 { 86 break; 87 } 88 } 89 if(i == MAX_EVENTS) 90 { 91 printf("%s:max connection limit[%d].", __func__, MAX_EVENTS); 92 break; 93 } 94 // set nonblocking 95 if(fcntl(nfd, F_SETFL, O_NONBLOCK) < 0) break; 96 // add a read event for receive data 97 EventSet(&g_Events[i], nfd, RecvData, &g_Events[i]); 98 EventAdd(g_epollFd, EPOLLIN|EPOLLET, &g_Events[i]); 99 printf("new conn[%s:%d][time:%d]\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), g_Events[i].last_active); 100 }while(0); 101 } 102 // receive data 103 void RecvData(int fd, int events, void *arg) 104 { 105 struct myevent_s *ev = (struct myevent_s*)arg; 106 int len; 107 // receive data 108 len = recv(fd, ev->buff, sizeof(ev->buff)-1, 0); 109 EventDel(g_epollFd, ev); 110 if(len > 0) 111 { 112 ev->len = len; 113 ev->buff[len] = '\0'; 114 printf("C[%d]:%s\n", fd, ev->buff); 115 // change to send event 116 EventSet(ev, fd, SendData, ev); 117 EventAdd(g_epollFd, EPOLLOUT|EPOLLET, ev); 118 } 119 else if(len == 0) 120 { 121 close(ev->fd); 122 printf("[fd=%d] closed gracefully.\n", fd); 123 } 124 else 125 { 126 close(ev->fd); 127 printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno)); 128 } 129 } 130 // send data 131 void SendData(int fd, int events, void *arg) 132 { 133 struct myevent_s *ev = (struct myevent_s*)arg; 134 int len; 135 // send data 136 len = send(fd, ev->buff, ev->len, 0); 137 ev->len = 0; 138 EventDel(g_epollFd, ev); 139 if(len > 0) 140 { 141 // change to receive event 142 EventSet(ev, fd, RecvData, ev); 143 EventAdd(g_epollFd, EPOLLIN|EPOLLET, ev); 144 } 145 else 146 { 147 close(ev->fd); 148 printf("recv[fd=%d] error[%d]\n", fd, errno); 149 } 150 } 151 void InitListenSocket(int epollFd, short port) 152 { 153 int listenFd = socket(AF_INET, SOCK_STREAM, 0); 154 fcntl(listenFd, F_SETFL, O_NONBLOCK); // set non-blocking 155 printf("server listen fd=%d\n", listenFd); 156 EventSet(&g_Events[MAX_EVENTS], listenFd, AcceptConn, &g_Events[MAX_EVENTS]); 157 // add listen socket 158 EventAdd(epollFd, EPOLLIN|EPOLLET, &g_Events[MAX_EVENTS]); 159 // bind & listen 160 sockaddr_in sin; 161 bzero(&sin, sizeof(sin)); 162 sin.sin_family = AF_INET; 163 sin.sin_addr.s_addr = INADDR_ANY; 164 sin.sin_port = htons(port); 165 bind(listenFd, (const sockaddr*)&sin, sizeof(sin)); 166 listen(listenFd, 5); 167 } 168 int main(int argc, char **argv) 169 { 170 short port = 12345; // default port 171 if(argc == 2){ 172 port = atoi(argv[1]); 173 } 174 // create epoll 175 g_epollFd = epoll_create(MAX_EVENTS); 176 if(g_epollFd <= 0) printf("create epoll failed.%d\n", g_epollFd); 177 // create & bind listen socket, and add to epoll, set non-blocking 178 InitListenSocket(g_epollFd, port); 179 // event loop 180 struct epoll_event events[MAX_EVENTS]; 181 printf("server running:port[%d]\n", port); 182 int checkPos = 0; 183 while(1){ 184 // a simple timeout check here, every time 100, better to use a mini-heap, and add timer event 185 long now = time(NULL); 186 for(int i = 0; i < 100; i++, checkPos++) // doesn't check listen fd 187 { 188 if(checkPos == MAX_EVENTS) checkPos = 0; // recycle 189 if(g_Events[checkPos].status != 1) continue; 190 long duration = now - g_Events[checkPos].last_active; 191 if(duration >= 60) // 60s timeout 192 { 193 close(g_Events[checkPos].fd); 194 printf("[fd=%d] timeout[%d--%d].\n", g_Events[checkPos].fd, g_Events[checkPos].last_active, now); 195 EventDel(g_epollFd, &g_Events[checkPos]); 196 } 197 } 198 // wait for events to happen 199 int fds = epoll_wait(g_epollFd, events, MAX_EVENTS, 1000); 200 if(fds < 0){ 201 printf("epoll_wait error, exit\n"); 202 break; 203 } 204 for(int i = 0; i < fds; i++){ 205 myevent_s *ev = (struct myevent_s*)events[i].data.ptr; 206 if((events[i].events&EPOLLIN)&&(ev->events&EPOLLIN)) // read event 207 { 208 ev->call_back(ev->fd, events[i].events, ev->arg); 209 } 210 if((events[i].events&EPOLLOUT)&&(ev->events&EPOLLOUT)) // write event 211 { 212 ev->call_back(ev->fd, events[i].events, ev->arg); 213 } 214 } 215 } 216 // free resource 217 return 0; 218 }
参考: