linux—TCP_server端编写之利用select()函数编写可多用户同时访问
2017-07-31 14:13
323 查看
1. 回顾多进程、多线程编写的server
之前我们编写了多进程、多线程的tcp_server,但我们发现虽然多线程和多进程的编写简单,但太占资源了,当客户端连接稍微多一点,服务器就有可能奔溃。所以我们今天要利用一种io模式:i/o复用(多路转接)2. 什么是多路转接
我们在IO数据时,通常时间是在等,我们普通read()函数,write()函数等一次只能等一个文件描述符,这样的效率太低了。所以我们就有了多路转接的IO方式,这种IO方式是,一次等待多个文件描述符,只要有一个就绪,则返回。3. 函数select
int select(int nfds, fd_set *readfds, fd_set *wirtefds,\ fd_set *exceptfds, struct timeval *timeout);
返回值:有多少个描述符就绪
nfds: 需要监视的文件描述符最大值+1;
rdset, wrset, exset分别对应于需要检测的可读⽂文件描述符的集合,可写⽂文件描述符的集 合及异常⽂文件描述符的集合。
struct timeval结构⽤用于描述 —— 一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。
4. 代码:
因为socket的创建,绑定,设置监听之前我已经写过了所以这里就不写了,有需要的可以点击链接参考参考:LINUX–TCP_server端的编写 创建监听套接字 listen_socket
int main(int argc, char *argv[]) { if(argc != 3){ usarg(argv[0]); return 0; } //提供手册,从命令行输入本地ip和端口号 int listen_sock = startup(argv[1], atoi(argv[2])); //listen_socke int fds[MAX] = {0}; // select的参数都是输入输出型的,需要自己记录文件描述符 int i = 0; fds[0] = listen_sock;//先将监听套接字添加到数组中 for(i=1; i<MAX; i++) { fds[i] = -1; }//清空数组 fd_set readfds; while(1) { FD_ZERO(&readfds); int count = listen_sock; for(i=0; i<MAX; i++) { if(fds[i] != -1) { count = ((count>fds[i])?count:fds[i]); FD_SET(fds[i], &readfds); }//添加数组的文件描述到参数readfds中,我们现在只关心读事件。 } int ret = select(count+1, &readfds, NULL, NULL, NULL); if(ret == 0)//我们设置的是阻塞式,所以基本不会==0 {printf("timeout!!!\n"); } else if(ret < 0)//出错 { perror("select"); return 5; } else if(ret > 0)//>0时,一定有文件描述符的那个事件就绪 { for(i=0; i<MAX; i++)//遍历判断是那个文件描述符的那个时间 { if(fds[i] == -1) continue; if(i == 0 && FD_ISSET(listen_sock, &readfds)) {//listen_socket的读事件就绪 struct sockaddr_in client; int len = sizeof(client); int new_sock = accept(listen_sock, (struct sockaddr *)&client, &len);//读 printf("client : [%s][%d],socket: [%d]\n" ,inet_ntoa(client.sin_addr),ntohs(client.sin_port),new_sock); for(i=4; i<MAX; i++ ) { if(fds[i] == -1) break; }//找数组中可以添加的位置,添加新的sock if(i == MAX) close(new_sock); else fds[i] = new_sock; } else if(FD_ISSET(fds[i], &readfds)) { char buf[1024]; ssize_t s= read(fds[i], buf, sizeof(buf)-1); if(s < 0) { perror("read"); } else if(s == 0) { printf("client[%d] quit!\n", fds[i]); close(fds[i]); fds[i] = -1; } else { printf("client[%d]: %s\n",fds[i],buf); } } } } } return 0; }
5. select函数的优点与缺点
优点:占用资源少,当用户多时性能较好缺点:1、select可监听的文件描述符有上限制;
2、因为select参数是输入输出型的,所以每次重新设置select时,都需遍历式设置,对性能有一定的影响
3、用户增多时,多次重复遍历和频繁内核与进程数据拷贝(多次的返回)
6.解决的办法
多路转接的函数还有poll. epoll ,epoll可以完全解决这个问题
相关文章推荐
- LINUX--TCP_server端的编写
- Linux TCP server系列(7)-select模式下的prefork server
- 编写求导函数的算法,利用原多项式的结点空间存放其异函数,同时释放所有无用节点
- Linux TCP server系列(6)-select模式下的多线程server
- linux驱动开发--copy_to_user 、copy_from_user函数实现内核空间数据与用户空间数据的相互访问
- Linux初学,利用共享内存,有名管道,select实现两个用户之间的自由对话。
- Linux TCP server系列(5)-select模式下的单进程server
- 【原创】TCP Socket 简单练习 --- select同时监测多个描述符 分类: Linux --- 应用程序设计 2014-12-23 10:33 75人阅读 评论(0) 收藏
- Linux网络编程:TCP服务器(单进程多用户),使用select方法实现
- [置顶] 编写shell脚本以及利用函数实现批量安装Linux服务配置
- Linux下利用glibc2库和crypt()函数生成用户密码
- Linux网络编程中tcp_server和tcp_client函数的封装
- [转]Linux 下给类tcp 通信模式的实现。select 函数
- 【从零开始,从内核驱动驱动到用户空间调用】编写第一个linux驱动,通过端口访问I/O寄存器。
- Linux TCP server系列(6)-select模式下的多线程server
- Linux下的单进程多用户TCP服务器,采用select方法实现。
- Linux TCP server系列(5)-select模式下的单进程server
- 【从零开始,从内核驱动驱动到用户空间调用】编写第一个linux驱动,通过端口访问I/O寄存器。
- Linux TCP server系列(6)-select模式下的多线程server