Linux网络编程【高并发服务器02_多路IO转接_select】

        多路IO转接服务器也叫做多任务IO服务器。该类服务器实现的主旨思想是,不再由应用程序自己监视客户端连接,取而代之由内核替应用程序监视文件。

可以理解为老板(服务器)聘一个小助手(select)帮助老板接听电话,有数据请求老板再做处理

多路IO转接: 响应模式 ==> 有数据来我才服务

select

文件描述符集合函数:

void FD_CLR(int fd, fd_set *set);
int  FD_ISSET(int fd, fd_set *set);
void FD_SET(int fd, fd_set *set);
void FD_ZERO(fd_set *set);

//void FD_ZERO(fd_set *set);    清空一个文件描述符集合
    fd_set rset;
    FD_ZERO(&rset);    类似于信号屏蔽字

//void FD_SET(int fd, fd_set *set);    将监听的文件描述符,添加到监听集合中
    FD_SET(3, &rset);
    FD_SET(4, &rset);
    FD_SET(5, &rset);
//void FD_CLR(int fd, fd_set *set);    将一个文件描述符从监听集合中移除

//int  FD_ISSET(int fd, fd_set *set);    判断一个文件描述符是否再监听集合中

 select函数

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

int select(int nfds, fd_set *readfds, fd_set *writefds,
        fd_set *exceptfds, struct timeval *timeout);

       参数:

                nfds:监听的所有文件描述符中,最大的文件描述符+1

                readfds:        读        文件描述符监听集合        传出,传出参数

                writefds:        写        文件描述符监听集合       传出,传出参数

                exceptfds:     异常      文件描述符监听集合      传出,传出参数

                timeout:        >0:设置超时时长

                                        =0:非监听阻塞,忙轮询

                                        NULL:阻塞监听

        返回值:

                >0:        所有监听集合中满足对应事件的总数

                0:          没有满足监听条件的文件描述符

                 <0:        异常,设置errno

思路分析:

    lfd = socket();                                        //创建监听套接字
    bind();                                                //绑定地址结构
    listen();                                              //设置监听上限

    fd_set rset, allset;                                   //创建rset
    FD_ZERO(&allset);                                      //清空rset
    FD_SET(lfd, &allset);                                  //将lfd添加到读集合中

    while(1) {
        rset = allset;                                     //allset可以看作是一个容器
        ret = select(lfd+1, &rset, NULL, NULL, NULL);
        if(ret > 0) {
            if(FD_INSET(lfd, &rset)) {
                cfd = accept();
                FD_SET(cfd, &allset);
            }
        }        
    }
    for(i = lfd+1, i <= maxfd, i++) {
        FD_ISSET(i, &rset);
        /*进行数据交换*/
    }

代码实现:

#include "wrap.h"
#define SER_PORT 9998
int main(int argc, char *argv[])
{
	int lfd;
	int cfd;
	socklen_t cli_len;
	char cli_IP[BUFSIZ];
	char buf[BUFSIZ];
	struct sockaddr_in ser_addr, cli_addr;
	ser_addr.sin_family = AF_INET;
	ser_addr.sin_port = htons(SER_PORT);
	ser_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	lfd = Socket(AF_INET, SOCK_STREAM, 0);
	Bind(lfd, (struct sockaddr *)&ser_addr, sizeof(ser_addr));
	Listen(lfd, 128);
	
	int ret, i, j, n;
	int maxfd= 0;
	maxfd = lfd;

	fd_set rset, allset;
	FD_ZERO(&allset);
	FD_SET(lfd, &allset);
	while(1) {
		rset = allset;
		ret = select(maxfd+1, &rset, NULL, NULL, NULL);
		
		if(ret < 0) 
			sys_exit("select error");		
	
		if(FD_ISSET(lfd, &rset)) {
			cli_len = sizeof(cli_addr);
			cfd = Accept(lfd, (struct sockaddr *)&cli_addr, &cli_len);
			
			FD_SET(cfd, &allset);
			if(maxfd < cfd)
				maxfd = cfd;
		
			if(ret == 1)		//select return 1 and it is lfd
				continue;
		}
		
		for(i = lfd+1; i < maxfd+1; i++) {
			if(FD_ISSET(i, &rset)) {	//first for continue	
				n = read(i, buf, sizeof(buf));
				if(n == 0) {
					close(i);
					FD_CLR(i, &allset);
				} else if(n == -1) {
					sys_exit("read error");
				}
				for(j = 0; j < n; j++) 
					buf[j] = toupper(buf[j]);

				write(i, buf, n);
				write(STDOUT_FILENO, buf, n);
			}
		}
	}
	return 0;
}

select

        缺点:监听上限受文件描述符上限影响

                检测满足条件的fd,自己添加业务逻辑提高效率但是提高了编码难度

        优点:跨平台

突破1024文件描述符限制方法:

        cat /proc/sys/fs/file-max        ==> 当前计算机所能打开的最大的文件个数。受硬件影响

        ulimit -a                                ==> 当前用户下的进程,默认打开文件描述符个数

        修改: sudo vi /etc/security/limits.conf

                *        soft nofile        20000

                *        hard nofile        30000

        hard的值要大于soft

                

  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值