IO复用,说得粗鄙一点,就是不用开多线程也能发送和接收消息。不多说,看代码:(select和poll是别人写的。引用一下,别见怪。)
select:
#include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/select.h> const static int MAXLINE = 1024; const static int SERV_PORT = 10001; int main() { int i , maxi , maxfd, listenfd , connfd , sockfd ; /*nready 描述字的数量*/ int nready ,client[FD_SETSIZE]; int n ; /*创建描述字集合,由于select函数会把未有事件发生的描述字清零,所以我们设置两个集合*/ fd_set rset , allset; char buf[MAXLINE]; socklen_t clilen; struct sockaddr_in cliaddr , servaddr; /*创建socket*/ listenfd = socket(AF_INET , SOCK_STREAM , 0); /*定义sockaddr_in*/ memset(&servaddr , 0 ,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(listenfd, (struct sockaddr *) & servaddr , sizeof(servaddr)); listen(listenfd , 100); /*listenfd 是第一个描述字*/ /*最大的描述字,用于select函数的第一个参数*/ maxfd = listenfd; /*client的数量,用于轮询*/ maxi = -1; /*init*/ for(i=0 ;i<FD_SETSIZE ; i++) client[i] = -1; FD_ZERO(&allset); FD_SET(listenfd, &allset); for (;;) { rset = allset; /*只select出用于读的描述字,阻塞无timeout*/ nready = select(maxfd+1 , &rset , NULL , NULL , NULL); if(FD_ISSET(listenfd,&rset)) { clilen = sizeof(cliaddr); connfd = accept(listenfd , (struct sockaddr *) & cliaddr , &clilen); /*寻找第一个能放置新的描述字的位置*/ for (i=0;i<FD_SETSIZE;i++) { if(client[i]<0) { client[i] = connfd; break; } } /*找不到,说明client已经满了*/ if(i==FD_SETSIZE) { printf("Too many clients , over stack .\n"); return -1; } FD_SET(connfd,&allset);//设置fd /*更新相关参数*/ if(connfd > maxfd) maxfd = connfd; if(i>maxi) maxi = i; if(nready<=1) continue; else nready --; } for(i=0 ; i<=maxi ; i++) { if (client[i]<0) continue; sockfd = client[i]; if(FD_ISSET(sockfd,&rset)) { n = read(sockfd , buf , MAXLINE); if (n==0) { /*当对方关闭的时候,server关闭描述字,并将set的sockfd清空*/ close(sockfd); FD_CLR(sockfd,&allset); client[i] = -1; } else { buf[n]=‘\0‘; printf("Socket %d said : %s\n",sockfd,buf); write(sockfd,buf,n); //Write back to client } nready --; if(nready<=0) break; } } } return 0; }
poll:
#include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <poll.h> /*环境为ubuntu10.04自带c环境,无法自动引入下列宏,所以自己写在前面了*/ #define INFTIM -1 #define POLLRDNORM 0x040 /* Normal data may be read. */ #define POLLRDBAND 0x080 /* Priority data may be read. */ #define POLLWRNORM 0x100 /* Writing now will not block. */ #define POLLWRBAND 0x200 /* Priority data may be written. */ #define MAXLINE 1024 #define OPEN_MAX 16 //一些系统会定义这些宏 #define SERV_PORT 10001 int main() { int i , maxi ,listenfd , connfd , sockfd ; int nready; int n; char buf[MAXLINE]; socklen_t clilen; struct pollfd client[OPEN_MAX]; struct sockaddr_in cliaddr , servaddr; listenfd = socket(AF_INET , SOCK_STREAM , 0); memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(listenfd , (struct sockaddr *) & servaddr, sizeof(servaddr)); listen(listenfd,10); client[0].fd = listenfd; client[0].events = POLLRDNORM; for(i=1;i<OPEN_MAX;i++) { client[i].fd = -1; } maxi = 0; for(;;) { nready = poll(client,maxi+1,INFTIM); if (client[0].revents & POLLRDNORM) { clilen = sizeof(cliaddr); connfd = accept(listenfd , (struct sockaddr *)&cliaddr, &clilen); for(i=1;i<OPEN_MAX;i++) { if(client[i].fd<0) { client[i].fd = connfd; client[i].events = POLLRDNORM; break; } } if(i==OPEN_MAX) { printf("too many clients! \n"); } if(i>maxi) maxi = i; nready--; if(nready<=0) continue; } for(i=1;i<=maxi;i++) { if(client[i].fd<0) continue; sockfd = client[i].fd; if(client[i].revents & (POLLRDNORM|POLLERR)) { n = read(client[i].fd,buf,MAXLINE); if(n<=0) { close(client[i].fd); client[i].fd = -1; } else { buf[n]=‘\0‘; printf("Socket %d said : %s\n",sockfd,buf); write(sockfd,buf,n); //Write back to client } nready--; if(nready<=0) break; //no more readable descriptors } } } return 0; }
epoll:
#include <stdio.h> #include <string.h> #include <arpa/inet.h> #include <netinet/in.h> #include <sys/socket.h> #include <poll.h> #include <stdlib.h> #include <errno.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <arpa/inet.h> #include <fcntl.h> #include <sys/epoll.h> #include <sys/time.h> #include <sys/resource.h> #define MAXLINE 1024 #define OPEN_MAX 16 //一些系统会定义这些宏 #define SERV_PORT 10001 int main() { int i , maxi ,listenfd , connfd , sockfd ,epfd, nfds; int n; char buf[MAXLINE]; struct epoll_event ev, events[20]; socklen_t clilen; struct pollfd client[OPEN_MAX]; struct sockaddr_in cliaddr , servaddr; listenfd = socket(AF_INET , SOCK_STREAM , 0); memset(&servaddr,0,sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); bind(listenfd , (struct sockaddr *) & servaddr, sizeof(servaddr)); listen(listenfd,10); epfd = epoll_create(256); ev.data.fd=listenfd; ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_ADD,listenfd,&ev); for(;;) { nfds=epoll_wait(epfd,events,20,500); for(i=0; i<nfds; i++) { if (listenfd == events[i].data.fd) { clilen = sizeof(cliaddr); connfd = accept(listenfd , (struct sockaddr *)&cliaddr, &clilen); if(connfd < 0) { perror("connfd < 0"); exit(1); } ev.data.fd=connfd; ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_ADD,connfd,&ev); } else if (events[i].events & EPOLLIN) { if ( (sockfd = events[i].data.fd) < 0) continue; n = recv(sockfd,buf,MAXLINE,0); if (n <= 0) { close(sockfd); events[i].data.fd = -1; } else { buf[n]=‘\0‘; printf("Socket %d said : %s\n",sockfd,buf); ev.data.fd=sockfd; ev.events=EPOLLOUT|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_MOD,connfd,&ev); } } else if( events[i].events&EPOLLOUT ) { sockfd = events[i].data.fd; send(sockfd, "Hello!", 7, 0); ev.data.fd=sockfd; ev.events=EPOLLIN|EPOLLET; epoll_ctl(epfd,EPOLL_CTL_MOD,sockfd,&ev); } else { printf("This is not avaible!"); } } } close(epfd); return 0; }
时间: 2025-01-14 16:19:59