Chinaunix首页 | 论坛 | 博客
  • 博客访问: 29332
  • 博文数量: 7
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 50
  • 用 户 组: 普通用户
  • 注册时间: 2016-06-10 15:39
个人简介

。。

文章分类

全部博文(7)

文章存档

2016年(7)

我的朋友

分类: 嵌入式

2016-06-11 16:17:56

【1】阻塞式IO模型
    最常见的、最简单、效率最低。
    读操作中的read、recv、recvfrom
    写操作中的write、send、sendto
    其他操作:accept、connect

【2】非阻塞式IO模型
    功能:可防止进程阻塞在IO操作上,但需要轮询、浪费CPU时间
    1)open()    :操作时可以指定为非阻塞得状态(O_NONBLOCK)
    
    2)int fcntl(int fd,int cmd,。。。/*arg可选项*/);
    功能:对文件的属性进行操作
    @cmd    :F_GETFL    获取文件标志位信息
                      F_SETFL    设置文件的标志信息
    返回值:    成功    0,或者    获取的值
                      出错    -1;
(注意:进行位操作的时候千万记得读、改、写,防止改变其他已有的状态)
    流程:
            int flags = 0;
            flags = fcntl(fd,F_GETFL);读
            flags &= ~O_NONBLOCK;改、设置非阻塞
            fcntl(fd,F_SETFL,flags);写

【3】多路IO复用(重点)对于TCP才有意义
    概念:先构造一张有关描述符的表,然后调用一个函数,当这些文件描述符中的一个或多个已准备好进行IO操作时,函数就返回告诉进程哪个已准备就绪了。

    1)int select(int nfds,fd_set *readfds,fd_set *writefds,fd_set exceptfds,struct timeval *time);
功能:监听多个文件描述符,阻塞等待有一个或者多个文件描述符,准备就绪。
           当监听到了之后,内核会将没有准备就绪的文件描述符,从集合中清掉了。所以下次又得重新将文件描述符添加进来;
    @nfds         :最大文件描述符数,加1
    @readfds    :读文件描述符集合
    @writefds    :写文件描述符集合
    @exceptfds  :其他异常的文件描述符集合,通常为NULL
    @timeout     :超时时间(不加超时就为NULL)
    返回值:
        当timeout 为NULL时,成功返回准备好的文件描述符,出错返回-1;
        当timeout不为NULL时,成功返回    准备好的文件描述符或者时间到达没有资源准备就绪就返回0,出错返回-1;
流程:
    1】创建TCP网络套接字                    socket();
    2】填充服务器信息到网络结构体当中 
    3】绑定网络套接字                           bind();
    4】设置监听模式                              listen();
    5】
/*清空readfds,tempfds    FD_ZERO();先把sockfd加进readfds,把sockfd       赋值给maxfd    FD_SET();完成初始化*/
    FD_ZERO(&readfds);
    FD_SET(sockfd, &readfds);
    maxfd = sockfd;

    while(1)
    {
        tempfds = readfds;    //设置一个临时的变量来保存已有的fd,因为select每次都会把集合剔除,所以要重新加入

        if(select(maxfd+1,&tempfds, NULL, NULL,NULL) < 0){
            err_log("fail to select");
        }
        for(i = 0; i < maxfd+1; i++){
            if(FD_ISSET(i, &tempfds)){    //查看有哪个fd的状态是准备就绪的
                if(i == sockfd){
                    if((acceptfd = accept(sockfd, (struct sockaddr*)&clientaddr, &addrlen)) < 0){
                        err_log("fail to accept");
                    }
                    maxfd = maxfd > acceptfd ? maxfd:acceptfd;//更新maxfd的值
                    FD_SET(acceptfd, &readfds);    //添加进readfds中
                }
                else{
                    if(recv(i, buf, N, 0) < 0){
                        err_log("fail to recv");
                    }
                    printf("server:%s\n", buf);
                    if(strncmp(buf, "quit", 4) == 0){
                        FD_CLR(i, &readfds);    //退出时要清除readfds中的该fd
                        close(i);
                        continue;
                    }
                    strcpy(buf, "Message from server.");
                    if(send(i, buf, N, 0) < 0){
                        err_log("fail to send");
                    }

                }

            }
        }
    }


    2)还可以用select+线程(思想就是select一直监听sockfd,然后接受一个创建一个线程去处理):
    FD_ZERO(&readfds);
    FD_ZERO(&tempfds);
    maxfd = sockfd;

    while(1){
        FD_SET(sockfd, &readfds);

        if(select(maxfd+1,&readfds, NULL, NULL,NULL) < 0){
            err_log("fail to select");
        }
        if((acceptfd = accept(sockfd, (struct sockaddr*)&clientaddr, &addrlen)) < 0){
            err_log("fail to accept");
        }
        if(pthread_create(&tid,NULL,recv_data,&acceptfd) < 0){
            err_log("fail to create pthread");
        }
        if(pthread_detach(tid) != 0){
            err_log("Fail to detach the pthread");
        }
    }     

    3)epoll套接字
    
    1】epoll_create函数
        函数声明:int epoll_create(int size)
       该函数生成一个epoll专用的文件描述符,其中的参数是指定生成描述符的最大范围。

   2】epoll_ctl函数
       函数声明:int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
       该函数用于控制某个文件描述符上的事件,可以注册事件,修改事件,删除事件。
    参数:
       @epfd:    由 epoll_create 生成的epoll专用的文件描述符;
       @op:    要进行的操作,可能的取值EPOLL_CTL_ADD 注册、EPOLL_CTL_MOD 修改、   EPOLL_CTL_DEL 删除;
       @fd:    关联的文件描述符;
       @event:    指向epoll_event的指针;
    返回值:
       如果调用成功则返回0,不成功则返回-1。

3】epoll_wait函数
   函数声明:int epoll_wait(int epfd,struct epoll_event * events,int maxevents,int timeout)
   该函数用于轮询I/O事件的发生。
   参数:
   @epfd:    由epoll_create 生成的epoll专用的文件描述符;
   @epoll_event:    用于回传代处理事件的数组;
   @maxevents:    每次能处理的事件数;
   @timeout:    等待I/O事件发生的超时值;
/**
     * size  表示你所关心的最大文件描述符的个数,只与内存有关
     * epollfd 非负的文件描述符,专用文件描述符,epoll实例的句柄
    */
    if((epollfd = epoll_create(10)) < 0)
    {
        err_log("fail to epoll_create");
    }

    //定义一个epoll事件,包括读,要监听的文件描述符
    ev.events = EPOLLIN;
    ev.data.fd = sockfd;

    //控制专用文件描述符,将sockfd 和 ev 添加到专用文件描述符上,完成注册
    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, sockfd, &ev) == -1) {
        err_log("fail to epoll_ctl");
    }

    for (;;) {
        pthread_mutex_lock(&mutex);
        // 等待专用文件描述符epollfd 上的事件的发生
        // events  待处理事件的数组,保存的是已经准备好的要处理的事件。
        // MAX_EVENTS  最大处理的事件数
        // nfds  返回发生的事件数
        if((nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1)) < 0)
        {
            pthread_mutex_unlock(&mutex);
            err_log("fail to epoll_wait");
        }
        pthread_mutex_unlock(&mutex);

        for (n = 0; n < nfds; ++n) {
            // 查看是那个事件发生了
            if(events[n].data.fd == sockfd) {
                if((acceptfd = accept(sockfd,(struct sockaddr *) &serveraddr, &addrlen)) < 0){
                    err_log("fail to accept");
                }
    //            set_non_blocking(acceptfd);  
                ev.events = EPOLLIN | EPOLLET;
                ev.data.fd = acceptfd;
                if (epoll_ctl(epollfd, EPOLL_CTL_ADD, acceptfd,&ev) == -1) {
                    err_log("fail to epoll_ctl");
                }
            } else {

                // 开启一个新的线程,专门用来处理对应客户端的请求
                pthread_t tid;

                if(pthread_create(&tid, NULL, pthread_client,&(events[n].data.fd)) < 0){
                    err_log("fail to pthread_create");
                }

            }
        }
    }






阅读(1649) | 评论(0) | 转发(0) |
0

上一篇:单链表

下一篇:链式队列

给主人留下些什么吧!~~