linux—TCP_server端编写之利用select()函数编写可多用户同时访问
来源:互联网 发布:国产网络腐剧 编辑:程序博客网 时间:2024/06/05 08:13
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可以完全解决这个问题
阅读全文
0 0
- linux—TCP_server端编写之利用select()函数编写可多用户同时访问
- Linux—TCP_server端编写多路转接之EPOLL
- LINUX--TCP_server端的编写
- 编写tcp_server
- XP 利用sp2可多用户同时登录
- Linux下select函数编写服务器
- 多进程多线程服务器(tcp_server)编写
- linux中select函数 实现多用户通信
- 编写可移植数据访问层
- 编写可移植数据访问层
- 编写可移植数据访问层
- 编写可移植数据访问层
- 编写可移植数据访问层
- 编写可移植数据访问层
- 编写可移植数据访问层
- 编写可移植数据访问层
- 编写可移植数据访问层
- 编写可移植数据访问层
- 总结Android Socket开发中可能遇到的问题
- ac自动机讲解
- 一个简单的Makefile
- C++类 内存对齐和类大小理解
- 兼容CommonJS
- linux—TCP_server端编写之利用select()函数编写可多用户同时访问
- MySQL笔记六
- PythonWebCrawler-模拟浏览器爬取信息
- ios 运行微信支付demo报错
- 【STL-deque】双向队列
- Linux下的多进程编程初步
- MySQL笔记七
- QT creator 获取多个屏幕分辨率
- 不适合使用shell的场景