select函数应用示例以及一些网络模型简单介绍

我们看到tcp客户同时处理两个输入:标准输入和tcp套接字。此时程序有了两个焦点,当客户阻塞于标准输入上是,服务器进程被杀死,服务器tcp虽然正确给客户tcp发送了一个fin,但是既然客户进程正阻塞于标准输入读入的过程,它将看不到这个eof,直到从套接字读时为止(可能已经过了很长时间),这样的进程需要一种预先告知内核的能力,使得内核一旦发现进程指定的一个i/o或者多个i/o条件就绪时它就通知进程,这个能力称为i/o复用。

I/O复用使用在下列网络场合:

1:当客户处理多个描述符(通常是交互式输入和网络套接字)时,必须使用i/o复用
2:如果一个tcp服务器既要处理监听套接字又要处理已连接套接字,一般就要使用i/o复用。
我们先来看看unix下的5种i/o模型的基本区别:
阻塞式,非阻塞式,i/o复用,信号驱动式,异步i/o
一个输入操作通常包括两个不同的阶段:
1)等待数据准备好
2)从内核向进程复制数据
阻塞式i/o模型:
           系统调用      内核       等待数据            将数据从内核复制到用户空间
recvfrom调用------------>无数据报准备好 ------------>数据报准备好复制数据报--------------------------->复制完成---->返回
非阻塞i/o模型
进程把一个套接字设置成非阻塞是在通知内核:当所请求的i/o操作非得把本进程投入睡眠才能完成时,不要把本进程投入睡眠,而是
返回一个错误。(recvfrom无数据时返回EWOULDBLOCK)
i/o复用模型:
有了i/o复用,我们就可以使用select或poll,阻塞在这两个系统调用中的某一个之上,而不是阻塞再真正的i/o系统调用上,
这种模型也可以使用多线程,每个线程阻塞于一个recvfrom之类的阻塞式i/o系统调用。
信号驱动式i/o模型
异步i/o模型
ok,下面给一个select使用模型。
int main(int argc,char* argv[]){
    int i,maxi,maxfd,listenfd,connfd,sockfd;
    int nready,client[FD_SETSIZE];
    sszie_t n;
    fd_set rset,allset.
    char buf[MAXLINE];
    socklen_t clilen;
    struct sockaddr_in cliaddr,servaddr;
    listenfd = socket(AF_INET,SOCK_STREAM,0);
    bzero(&servaddr,sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);
    bind(listenfd,(SA*)&servaddr,sizeof(servaddr));
    listen(listenfd,LISTENQ);
    maxfd = listenfd;
    maxi = -1;
    for(int i = 0;i < FD_SETSIZE;i++){
        client[i] = -1;
    }
    FD_ZERO(&allset);
    FD_SET(listenfd,&allset);
    for(;;) {
        rset = allset;
        nready = select(maxfd+1,&rset,NULL,NULL,NULL);
        if(FD_ISSET(listenfd,&rset)){
             clilen = sizeof(cliaddr);
             connfd = accept(listenfd,(SA*)&cliaddr,&clilen);
             for(i =0;i < FD_SETSIZE;++i){
                  if(client[i] < 0){
          client[i]=connfd;
                      break;
      }
             }
             if(i == FD_SETSIZE)
     exit(-1);//too many clients;

            FD_SET(connfd,&allset);
             if(connfd > maxfd)
    maxfd = connfd;
             if(i > maxi)
    maxi = i;
            if(--nready <= 0)
    continue;         
        }
    }
    for(i = 0;i <= maxi;i++){
        if((sockfd = client[i]) < 0)
    continue;
      if(FD_ISSET(sockfd,&allset)){
           if((n = read(sockfd,buf,MAXLINE)) == 0){
    close(sockfd);
    FD_CLR(sockfd,&allset);
    client[i] = -1;
           }else{
     write(sockfd,buf,n);
           }
           if(--nready <= 0)
    break;
      } 
    }  
}

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值