多路转接服务器之select
2017-08-01 22:38
344 查看
多路转接server之select
多路转接是5种I/O模型中的一种,I/O分为两步,第一步等I/O事件就绪,第二步对数据进行I/O,提高I/O效率实质上是要减少等的时间的比重。I/O模型分为5种:阻塞式I/O
非阻塞轮循式I/O
信号驱动式I/O
多路转接I/O
异步I/O
前四种是同步I/O,即自己等自己进行数据搬迁。后一种是异步I/O,即自己发起让底层去做,做好了通知我。
阻塞/非阻塞,都是同步I/O,前者是死等,后者是只要I/O条件不成熟就返回。
select_server
#include<stdio.h> #include<stdlib.h> #include<unistd.h> #include<fcntl.h> #include<netinet/in.h> #include<string.h> #include<sys/socket.h> #include<sys/types.h> #include<sys/select.h> static void usage(char* proc) { printf("Usage :%s [local_ip] [local_port]\n",proc); } int startup(const char *ip, int port) { int sock = socket(AF_INET, SOCK_STREAM, 0); if(sock < 0){ perror("socket"); exit(1); } struct sockaddr_in local; local.sin_family = AF_INET; local.sin_port = htons(port); local.sin_addr.s_addr = inet_addr(ip); if(bind(sock, (struct sockaddr*)&local, sizeof(local)) < 0){ perror("bind"); exit(2); } if(listen(sock, 10) < 0){ perror("listen"); exit(4); } return sock; } int fds[1024];//定义全局数组用来存放就绪的文件描述符 int main(int argc, char *argv[]) { if(argc != 3){//用户不会使用时打印使用手册 usage(argv[0]); reutrn 1; } int listen_sock = startup(argv[1], atoi(argv[2])); fd_set rfds;//创建一个文件描述符集 int nums = sizeof(fds)/sizeof(fds[0]); int i = 0; for(; i < 1024; i++){// fd都为非负数所以初始化为-1表明没有存放 fds[i] = -1; } fds[0] = listen_sock;// 将监听套接字放在0号下标处 while(1){ int maxfd = -1; struct timeval timeout = {0, 0}; FD_ZERO(&rfds);// 清空文件描述符集 for(i=0; i < nums; i++){ if(fds[i] == -1){//找一个没有被占的位置 continue; } FD_SET(fds[i], &rfds);// 把这个fd[i]放进fd集中 if(maxfd < fds[i]){ maxfd = fds[i];// 修改最大的文件描述符 } } switch(select(maxfd+1, &rfds, NULL, NULL, NULL)) { case 0: perror("timeout"); break; case -1: perror("select"); close(fd[i]); break; default: { for(i = 0; i < nums; i++){ if(i == 0 && FD_ISSET(fds[i], &rfds)){//说明监听套接字已经就绪 struct sockaddr_in client; socklen_t len = sizeof(client); int new_sock = accept(listen_sock\ , (struct sockaddr*)&client, &len); printf("[%s:%d]\n",inet_ntoa(client.sin_addr), ntohs(client.sin_port)); if(new_sock < 0){ perror("accept"); continue; } int j = 0; for(; j < nums; j++){//遍历数组寻找空位 if(fds[j] == -1){ break; } } if(j == nums){//说明放不下了关闭接收套接字 close(new_sock); }else{ fds[j] = new_sock; } }else if(i != 0 && FD_ISSET(fds[i]\ , &rfds)){// 别的事件已就绪 char buf[1024]; ssize_t s = read(fds[i], buf\ , sizeof(buf)-1); if(s > 0){ buf[s] = 0; printf("client say# %s\n", buf); write(fds[i], buf, strlen(buf)); }else if(s == 0){ printf("client quit!!!\n"); close(fds[i]); fds[i] = -1; }else{ perror("read"); close(fds[i]); fds[i] = -1; } }else{ } } } break; }; } return 0; }
测试结果:
可以一次被多个client连接,相比较多进程多线程select_server服务器当用户量较大时性能更好,而且它所占的资源是较少的。但是呢它还是有很多的缺点滴
每次调用select时都要把fd从用户态拷贝到内核态,这在fd很多时系统开销会很大
每次调用select都要在内核遍历所有传递进来的fd,在fd很多时系统开销也会很大
所能处理的fd数量有限,因为它是一个集合,是集合就有大小
相关文章推荐
- Linux下高级I/O多路转接之select服务器
- I/O多路转接之select服务器
- Linux网络编程【五】:TCP协议高性能服务器(http)模型之I/O多路转接select
- I/O多路转接之select服务器
- 【Linux网络编程】基于TCP协议 I/O多路转接(select) 的高性能回显服务器客户端模型
- Linux高性能服务器之多路转接(1)----select模型实现
- (五十三)高并发服务器——多路IO转接机制Select模型
- Linux【网络编程】——I/O多路转接之Select服务器
- 高性能服务器——I/O多路转接的三种模式(select &poll& epoll)
- I/O多路转接----select的服务器实现
- 【Linux】多路 IO转接服务器 — select
- 服务器与客户端的模型之select的多路转接
- 实现多路转接I/O——select服务器
- I/O多路转接----select
- I/O多路转接之select
- 多路转接模型服务器和客户端的实现
- 多路转接服务器之poll
- 多路转接之poll和select
- Linux网络编程【六】:TCP协议高性能服务器(http)模型之I/O多路转接epoll
- I/O多路转接之select