美文网首页
Linux-C-8-IO复用

Linux-C-8-IO复用

作者: 秋风弄影 | 来源:发表于2017-06-29 00:49 被阅读0次

    概念

    IO复用:用于表示多个网络链接复用一个IO线程,具有开销小的优点,但是同样的编程的复杂度就会比较高;

    IO复用使用的几个函数

    select
    int select (int maxfd,fd_set *rdset,fd_set*wrset,fd_set *exset,struct timeval *timeout);
    

    maxfd:表示需要监视的最大文件描述符值+1;
    rdset:需要检测的刻度文件描述符集合;
    wrset:需要检测的可写文件描述符集合;
    exset:需要检测的异常文件描述符集合;
    timeout:超时时间
    返回值:-1表示出错,0表示超时,>0表示获取到的数据;
    同时还需要掌握的几个函数包括:
    FD_ZERO(fd_set *fdset):用于清空文件描述符集合

    fd_set rfds;
    FD_ZERO(&RFDS);
    

    FD_SET(int fd,fd_set *fd_set):向文件描述符中增加一个新的文件描述符

    FD_SET(listenfd,&rfds);
        int maxfdp1 = listenfd + 1;
        int connfds[FD_SETSIZE-1];  
        size_t connfds_cnt = 0;
        for(;;){
            int i;
            FD_SET(listenfd,&rfds);
            for(i=0;i<connfds_cnt;i++){
                FD_SET(connfds[i],&rfds);
                printf("FD_SET(%d)\n",connfds[i]);
            }
    

    FD_CLR(int fd, fd_set *fdset):在文件描述符集合中删除应文件描述符

    if(0 == len){
            printf("close %d\n",connfds[i]);
            close(connfds[i]);
            FD_CLR(connfds[i],&rfds);
            memcpy(connfds+i,connfd+i+1,connfds_cnt-i-1);
            connfds_cnt--;
            i--;
            continue;
        }
    
    

    FD_ISSET(int fd,fd_set *fdset):用于测试指定的文件描述符是否在该集合中;

    if(FD_ISSET(connfds[i],&rfds)){
    
        char buf[BUFSIZ];
        bzero(buf,BUFSIZ);
        ssize_t len;
        if((len = read(connfds[i],buf,BUFSIZ-1)) == -1){
                  perror("read err");
                  //return 1;
        }
        if(0 == len){
                  printf("close %d\n",connfds[i]);
                  close(connfds[i]);
                  FD_CLR(connfds[i],&rfds);
                  memcpy(connfds+i,connfd+i+1,connfds_cnt-i-1);
                  connfds_cnt--;
                  i--;
                 continue;
            }
    }
    

    FD_SETSIZE:是一个常数值表示的是265;
    提供一个完整的tcp_server_select.c程序:

    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <sys/select.h>
    
    #define max(a,b) ((a)>(b)?(a):(b))
    void show_info(int connfd){
        struct sockaddr_in local_addr;
        bzero(&local_addr,sizeof(local_addr));
        socklen_t local_addr_len = sizeof(local_addr);
        getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
        printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
        
        struct sockaddr_in peer_addr;
        bzero(&peer_addr,sizeof(peer_addr));
        socklen_t peer_addr_len = sizeof(peer_addr);
        getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
        printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
    }
    int main(int argc,char* argv[]){
        if(3 != argc){
            printf("usage:%s <ip> <#port>\n",argv[0]);
            return 1;
        }
    
        int listenfd = socket(AF_INET,SOCK_STREAM,0);
        if(-1 == listenfd){
            perror("listenfd open err");
            return 1;
        }
        printf("socket create OK\n");
        
        int flag = 1;
        setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));    
    
        struct sockaddr_in local_addr;
        bzero(&local_addr,sizeof(local_addr));
        local_addr.sin_family = AF_INET;
        local_addr.sin_addr.s_addr = inet_addr(argv[1]);
        local_addr.sin_port = htons(atoi(argv[2]));
    
        if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
            perror("bind err");
            return 1;
        }
        printf("bind OK\n");
    
        if(-1 == listen(listenfd,10)){
            perror("listen err");
            return 1;
        }
        printf("listen OK\n");
    
        fd_set rfds;
        FD_ZERO(&rfds);
        
        FD_SET(listenfd,&rfds);
        int maxfdp1 = listenfd + 1;
        int connfds[FD_SETSIZE-1];  
        size_t connfds_cnt = 0;
        for(;;){
            int i;
            FD_SET(listenfd,&rfds);
            for(i=0;i<connfds_cnt;i++){
                FD_SET(connfds[i],&rfds);
                printf("FD_SET(%d)\n",connfds[i]);
            }
            printf("before select:%lu\n",rfds);
            if(-1 == select(maxfdp1,&rfds,NULL,NULL,NULL)){
                perror("select error");
                return 1;
            }
            printf("after select:%lu\n",rfds);
            if(FD_ISSET(listenfd,&rfds)){
                printf("listenfd ready\n");
                struct sockaddr_in remote_addr;
                bzero(&remote_addr,sizeof(remote_addr));
                socklen_t remote_addr_len = sizeof(remote_addr);
                int connfd = accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
                if(-1 == connfd){
                    perror("accept err");
                    //return 1;
                }
    
                if(connfds_cnt+1 == FD_SETSIZE-1){
                    fprintf(stderr,"connfd size over %d\n",FD_SETSIZE-1);
                    close(connfds[i]);
                }else{
                    connfds[connfds_cnt++] = connfd;                
                    maxfdp1 = max(connfd,maxfdp1-1)+1;
                    show_info(connfd);
                }
            }
            for(i=0;i<connfds_cnt;i++){
                if(-1 == connfds[i]){
                    continue;
                }
                if(FD_ISSET(connfds[i],&rfds)){
    
                    char buf[BUFSIZ];
                    bzero(buf,BUFSIZ);
                    ssize_t len;
                    if((len = read(connfds[i],buf,BUFSIZ-1)) == -1){
                        perror("read err");
                        //return 1;
                    }
                    if(0 == len){
                        printf("close %d\n",connfds[i]);
                        close(connfds[i]);
                        FD_CLR(connfds[i],&rfds);
                        memcpy(connfds+i,connfd+i+1,connfds_cnt-i-1);
                        connfds_cnt--;
                        i--;//鏁扮粍鍙戠敓鍙樺寲锛岄噸鏂板垽鏂璱鐨刦d
                        continue;
                    }
                    printf("server recv:%s\n",buf);
                    
                    int fd = open(buf,O_RDONLY);
                    if(-1 == fd){
                        perror("open file err");
                    }
                    struct stat file_stat;
                    fstat(fd,&file_stat);
                    if(-1 == sendfile(connfds[i],fd,NULL,file_stat.st_size)){
                        perror("sendfile err");
                    }
                    printf("server send file %s ok\n",buf);
                    close(fd);
                }
            }
        }
        close(listenfd);
    
    }
    

    对于select模式的缺点:
    1、需要修改传入的参数数组;
    2、不能够确切指定有数据的socket;
    3、只能够监视FD_SETSIZE数目个连接;
    4、线程不安全;

    Poll模式

    Poll模式具备的优点:
    1、不需要修改传入的参数数组
    2、可以监视任意个连接,可以通过cat /proc/sys/file-max进行查看
    缺点:
    1、不能够确切的指定有数据的socket
    2、线程不安全
    poll模型需要使用的函数是int poll(struct pollfd *fdarray,usigned long nfds,int timeout);

    struct pollfd *fdarray {
              fd:表示文件描述符号
              struct profile{
                        events:表示监视的事件;
                        revents:表示实际发生的事件;
              };
    };
    

    对于events支持的选项有:
     输入:POLLRDNOPM:表示普通数据;POLLRDBAND:优先级带数据;POLLIN:普通或者优先级带数据;
     输出:POLLWRNOPM:表示普通数据;POLLWRBAND:优先级带数据;POLLOUT:普通或者优先级带数据;
    对于revents支持的选项包括:
     输入:POLLRDNOPM:普通数据;POLLRDBAND:优先级带数据;POLLIN:普通或者优先级带数据;
     输出:POLLWRNORW:普通数据;POLLWRBAND:优先级带数据;POOLLOUT:普通或者优先级带数据;
     错误:POLLERR:发生错误;POLLHUP:发生挂起;POLLNVAL:描述符非法;

    No 常量 events revents 说明
    1 POLLIN OK OK 普通或者优先级带数据可读;
    2 POLLRDNORM OK OK 普通数据可读
    3 POLLRDBAND OK OK 优先级带数据可读
    4 POLLPRI OK OK 高优先级数据可读
    5 POLLOUT OK OK 普通数据可写
    6 POLLWRNORM OK OK 普通数据可写
    7 POLLWRBAND OK OK 优先级带数据可写
    8 POLLERR NG OK 发生错误
    9 POLLHUP NG OK 发生挂起
    10 POLLNVAL NG OK 描述字不是一个打开的文件

    其余的参数的含义
     nfds:表示数组元素的个数;
     timeout;用于定义等待的时间;INFTIM:表示永久等待;0:表示立即返回;>0:表示等待描述;
     返回值0:表示超时;-1:表示出错;正数:表示就绪的描述符的个数;
    普通数据:表示的含义是正规的TCP数据以及所有的UDP数据;优先级带数据:表示TCP带外的数据;

    tcp_server_poll.c

    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <sys/poll.h>
    #include <linux/fs.h>
    
    #define max(a,b) ((a)>(b)?(a):(b))
    void show_info(int connfd){
        struct sockaddr_in local_addr;
        bzero(&local_addr,sizeof(local_addr));
        socklen_t local_addr_len = sizeof(local_addr);
        getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
        printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
        
        struct sockaddr_in peer_addr;
        bzero(&peer_addr,sizeof(peer_addr));
        socklen_t peer_addr_len = sizeof(peer_addr);
        getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
        printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
    }
    int main(int argc,char* argv[]){
        if(3 != argc){
            printf("usage:%s <ip> <#port>\n",argv[0]);
            return 1;
        }
    
        int listenfd = socket(AF_INET,SOCK_STREAM,0);
        if(-1 == listenfd){
            perror("listenfd open err");
            return 1;
        }
        printf("socket create OK\n");
        
        int flag = 1;
        setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));    
    
        struct sockaddr_in local_addr;
        bzero(&local_addr,sizeof(local_addr));
        local_addr.sin_family = AF_INET;
        local_addr.sin_addr.s_addr = inet_addr(argv[1]);
        local_addr.sin_port = htons(atoi(argv[2]));
    
        if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
            perror("bind err");
            return 1;
        }
        printf("bind OK\n");
    
        if(-1 == listen(listenfd,10)){
            perror("listen err");
            return 1;
        }
        printf("listen OK\n");
    
        struct pollfd poll_fd[INR_OPEN_MAX];
        poll_fd[0].fd = listenfd;
        poll_fd[0].events = POLLRDNORM;
        size_t poll_fd_cnt = 1;
    
        for(;;){
            if(-1 != poll(poll_fd,poll_fd_cnt,-1)){
                if(poll_fd[0].revents == POLLRDNORM){
                    printf("accept listenfd\n");
                    int connfd = accept(listenfd,NULL,NULL);
                    if(-1 == connfd){
                        perror("accept err");
                    }else{
                        if(poll_fd_cnt+1 == INR_OPEN_MAX){
                            fprintf(stderr,"connfd size over %d",INR_OPEN_MAX);
                            close(connfd);
                        }else{
                            poll_fd[poll_fd_cnt].fd = connfd;
                            poll_fd[poll_fd_cnt].events = POLLRDNORM;
                            poll_fd_cnt++;
                        }
                    }
                }
                int i;
                for(i=1;i<poll_fd_cnt;i++){
                    if(poll_fd[i].revents & POLLRDNORM){    
                        char buf[BUFSIZ];
                        bzero(buf,BUFSIZ);
                        ssize_t len;
                        printf("read connfd %d\n",poll_fd[i].fd);
                        if((len = read(poll_fd[i].fd,buf,BUFSIZ-1)) == -1){
                            perror("read err");
                            //return 1;
                        }
                        if(0 == len){
                            printf("close %d\n",poll_fd[i].fd);
                            printf("%d vs %d\n",poll_fd[i].revents,poll_fd[i].revents);
                            close(poll_fd[i].fd);
                            printf("%d vs %d\n",poll_fd[i].revents,poll_fd[i].revents);
                            memcpy(poll_fd+i,poll_fd+i+1,poll_fd_cnt-i-1);
                            poll_fd_cnt--;
                            i--;                                                  
                             continue;
                            //break;
                        }
                        printf("server recv:%s\n",buf);
                        
                        int fd = open(buf,O_RDONLY);
                        if(-1 == fd){
                            perror("open file err");
                        }
                        struct stat file_stat;
                        fstat(fd,&file_stat);
                        if(-1 == sendfile(poll_fd[i].fd,fd,NULL,file_stat.st_size)){
                            perror("sendfile err");
                        }
                        printf("server send file %s ok\n",buf);
                        close(fd);
                    }
                }
            }
        }
    
        close(listenfd);
    }
    

    tcp_client_poll.c

    #include <stdio.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <sys/select.h>
    #include <math.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/poll.h>
    
    #define max(a,b) ((a)>(b)?(a):(b))
    
    void show_info(int connfd){
        struct sockaddr_in local_addr;
        bzero(&local_addr,sizeof(local_addr));
        socklen_t local_addr_len = sizeof(local_addr);
        getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
        printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
        
        struct sockaddr_in peer_addr;
        bzero(&peer_addr,sizeof(peer_addr));
        socklen_t peer_addr_len = sizeof(peer_addr);
        getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
        printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
    }
    int main(int argc,char* argv[]){
        if(3 != argc){
            printf("usage:%s <ip> <#port> \n",argv[0]);
            return 1;
        }
    
        int connfd = socket(AF_INET,SOCK_STREAM,0);
        if(-1 == connfd){
            perror("socket err");
            return 1;
        }
        struct sockaddr_in remote_addr;
        bzero(&remote_addr,sizeof(remote_addr));
        remote_addr.sin_family = AF_INET;
        remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
        remote_addr.sin_port = htons(atoi(argv[2]));    
        if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
            perror("connect err");
            return 1;
        }
    
        show_info(connfd);
    
        printf("connfd:%d\n",connfd);
    
        struct pollfd poll_fds[2];
    
        poll_fds[0].fd = connfd;
        poll_fds[0].events = POLLRDNORM;
        poll_fds[1].fd = STDIN_FILENO;
        poll_fds[1].events = POLLRDNORM;
    
        char buf[BUFSIZ];
        for(;;){
            if(-1 != poll(poll_fds,2,-1)){
                if(poll_fds[0].fd == connfd && poll_fds[0].revents & POLLRDNORM){
                    bzero(buf,BUFSIZ);
                    printf("recv msg\n");
                    ssize_t n;
                    if((n = read(connfd,buf,BUFSIZ)) == -1){
                        perror("read err");
                        return 1;
                    }else if(0 == n){
                        printf("server close\n");
                        break;
                    }
                    printf("client recv:%s\n",buf);
                }
                if(poll_fds[1].fd == STDIN_FILENO && poll_fds[1].revents & POLLRDNORM){
                    bzero(buf,BUFSIZ);
                    printf("send msg\n");
                    fgets(buf,BUFSIZ,stdin);
                    write(connfd,buf,strlen(buf)-1);
                }
            }
        }
    
        close(connfd);
    }
    
    EPOLL模型

    优点:能够确切地指定有数据的socket,并且线程是安全的;

    Epoll模型的创建

    使用函数int eploo_create(int size)来进行创建,size用于指定监听的数目,返回值通常是文件描述符,在/proc/进程ID/fd可以进行查看;

    struct sockaddr_in local_addr;
        bzero(&local_addr,sizeof(local_addr));
        local_addr.sin_family = AF_INET;
        local_addr.sin_addr.s_addr = inet_addr(argv[1]);
        local_addr.sin_port = htons(atoi(argv[2]));
    
        if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
            perror("bind err");
            return 1;
        }
        printf("bind OK\n");
    
        if(-1 == listen(listenfd,10)){
            perror("listen err");
            return 1;
        }
        printf("listen OK\n");
    
    
        int epoll_fd = epoll_create(INR_OPEN_MAX);
    
    Epoll模型的控制
    Epoll_event 说明
    EPOLLOUT 表示对应的文件描述符可写
    EPOLLPRI 表示对应的文件描述符有紧急的数据可读
    EPOLLERR 表示对应文件描述符发生错误
    EPOLLHUP 表示对应的文件描述符被挂断
    EPOLLET 表示对应的文件描述符设定为edge模式

    使用函数int epoll_ctl(int epfd,int op,int fd, struct epoll_event *event);来进行epoll模型的控制;
    epfd:表示epoll文件描述符;
    op:用于定义对于文件描述符的操作,EPOLL_CTL_ADD:表示用于创建;EPOLL_CTL_MOD:表示用于修改某些类型;EPOLL_CTL_DEL:表示用于删除;fd:表示相互关联的文件描述符;event:表示指向epoll_event的指针;

    Epoll_event 说明
    EPOLLOUT 表示对应的文件描述符可写
    EPOLLPRI 表示对应的文件描述符有紧急的数据可读
    EPOLLERR 表示对应文件描述符发生错误
    EPOLLHUP 表示对应的文件描述符被挂断
    EPOLLET 表示对应的文件描述符设定为edge模式

    返回值:0表示成功,-1表示失败;

            struct epoll_event evt;
        evt.data.fd = listenfd;
        evt.events = EPOLLIN;
        epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listenfd,&evt);
    
    
    轮询IO事件

    int epoll_wait(int epfd,struct epoll_event events,int max events,int timeout);
    epfd:表示epoll文件描述符;
    epoll_events:用于回传待处理事件的数组;
    maxevents:每次能够处理的事件数;
    timeout:等待IO事件发生的超时值;-1表示永不超时;0表示立即返回;
    返回值:正数表示发生事件数;-1:表示错误;

    struct epoll_event out_evts[out_evts_cnt];
            int fd_cnt = epoll_wait(epoll_fd,out_evts,out_evts_cnt,-1);
    
    Epoll模型的两种模式:

    ET(Edge Triggered)模式
    LT(Level Triggered)模式
    1、表示管道读者的文件句柄注册到epoll中;
    2、管道写着向管道写入2KB的数据;
    3、调用epoll_wait可以获得管道读者已经就绪的文件句柄;
    4、管道读者读取1Kb的数据;
    5、一次epoll_wait调用完成;
    如果执行的是ET模式,管道中剩余的1Kb数据就会被挂起,等待再次调用epoll_wait(),得不到管道读者的文件句柄,除非有新的数据写入管道,如果是LT模式,只要管道中有数据可读,每次调用epoll_wait()都会触发;
    还有一点区别就是设为ET模式的文件句柄必须是非阻塞的;

    tcp_server_epoll.c

    #include <stdio.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <sys/select.h>
    #include <math.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <sys/epoll.h>
    
    #define max(a,b) ((a)>(b)?(a):(b))
    
    void show_info(int connfd){
        struct sockaddr_in local_addr;
        bzero(&local_addr,sizeof(local_addr));
        socklen_t local_addr_len = sizeof(local_addr);
        getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
        printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
        
        struct sockaddr_in peer_addr;
        bzero(&peer_addr,sizeof(peer_addr));
        socklen_t peer_addr_len = sizeof(peer_addr);
        getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
        printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
    }
    int main(int argc,char* argv[]){
        if(3 != argc){
            printf("usage:%s <ip> <#port> \n",argv[0]);
            return 1;
        }
    
        int connfd = socket(AF_INET,SOCK_STREAM,0);
        if(-1 == connfd){
            perror("socket err");
            return 1;
        }
        struct sockaddr_in remote_addr;
        bzero(&remote_addr,sizeof(remote_addr));
        remote_addr.sin_family = AF_INET;
        remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
        remote_addr.sin_port = htons(atoi(argv[2]));    
        if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
            perror("connect err");
            return 1;
        }
    
        show_info(connfd);
    
        printf("connfd:%d\n",connfd);
    
        struct epoll_event in_evts[2];
    
        in_evts[0].data.fd = connfd;
        in_evts[0].events = EPOLLIN;
        in_evts[1].data.fd = STDIN_FILENO;
        in_evts[1].events = EPOLLIN;
        
        int epoll_fd = epoll_create(2);
    
        epoll_ctl(epoll_fd,EPOLL_CTL_ADD,connfd,in_evts);
        epoll_ctl(epoll_fd,EPOLL_CTL_ADD,STDIN_FILENO,in_evts+1);
    
        char buf[BUFSIZ];
        for(;;){
            struct epoll_event out_evts[2];
            int fd_cnt = epoll_wait(epoll_fd,out_evts,2,-1);
            
            int i;
            for(i=0;i<fd_cnt;i++){
                if(out_evts[i].data.fd == connfd && out_evts[i].events & EPOLLIN){
                    
                    bzero(buf,BUFSIZ);
                    printf("recv msg\n");
                    ssize_t n;
                    if((n = read(connfd,buf,BUFSIZ)) == -1){
                        perror("read err");
                        return 1;
                    }else if(0 == n){
                        printf("server close\n");
                        break;
                    }
                    printf("client recv:%s\n",buf);
                }
                if(out_evts[i].data.fd == STDIN_FILENO && out_evts[i].events & EPOLLIN){
    
                    bzero(buf,BUFSIZ);
                    printf("send msg\n");
                    fgets(buf,BUFSIZ,stdin);
                    write(connfd,buf,strlen(buf)-1);
                }
            }       
        }
    
        close(connfd);
    }
    

    tcp_client_epoll.c

    #include <stdio.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <sys/socket.h>
    #include <sys/epoll.h>
    #include <linux/fs.h>
    
    #define max(a,b) ((a)>(b)?(a):(b))
    void show_info(int connfd){
        struct sockaddr_in local_addr;
        bzero(&local_addr,sizeof(local_addr));
        socklen_t local_addr_len = sizeof(local_addr);
        getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
        printf("server local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
        
        struct sockaddr_in peer_addr;
        bzero(&peer_addr,sizeof(peer_addr));
        socklen_t peer_addr_len = sizeof(peer_addr);
        getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
        printf("server peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
    }
    int main(int argc,char* argv[]){
        if(3 != argc){
            printf("usage:%s <ip> <#port>\n",argv[0]);
            return 1;
        }
    
        int listenfd = socket(AF_INET,SOCK_STREAM,0);
        if(-1 == listenfd){
            perror("listenfd open err");
            return 1;
        }
        printf("socket create OK\n");
        
        int flag = 1;
        setsockopt(listenfd,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));    
    
        struct sockaddr_in local_addr;
        bzero(&local_addr,sizeof(local_addr));
        local_addr.sin_family = AF_INET;
        local_addr.sin_addr.s_addr = inet_addr(argv[1]);
        local_addr.sin_port = htons(atoi(argv[2]));
    
        if(-1 == bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr))){
            perror("bind err");
            return 1;
        }
        printf("bind OK\n");
    
        if(-1 == listen(listenfd,10)){
            perror("listen err");
            return 1;
        }
        printf("listen OK\n");
    
    
        int epoll_fd = epoll_create(INR_OPEN_MAX);
    
        struct epoll_event evt;
        evt.data.fd = listenfd;
        evt.events = EPOLLIN;
        epoll_ctl(epoll_fd,EPOLL_CTL_ADD,listenfd,&evt);
    
        int out_evts_cnt = 1;
        for(;;){
            struct epoll_event out_evts[out_evts_cnt];
            int fd_cnt = epoll_wait(epoll_fd,out_evts,out_evts_cnt,-1);
            int i;
            for(i=0;i<fd_cnt;i++){
                if(out_evts[i].data.fd == listenfd && out_evts[i].events & EPOLLIN){
    
                    printf("accept listenfd\n");
                    int connfd = accept(listenfd,NULL,NULL);
                    if(-1 == connfd){
                        perror("accept err");
                    }else{
                        if(out_evts_cnt+1 == INR_OPEN_MAX){
                            fprintf(stderr,"connfd size over %d",INR_OPEN_MAX);
                            close(connfd);
                        }else{
                            struct epoll_event evt;
                            evt.data.fd = connfd;
                            evt.events = EPOLLIN;
                            epoll_ctl(epoll_fd,EPOLL_CTL_ADD,connfd,&evt);
                            out_evts_cnt++;
                        }
                    }
                }else if(out_evts[i].events & EPOLLIN){
    
                        char buf[BUFSIZ];
                        bzero(buf,BUFSIZ);
                        ssize_t len;
                        printf("read connfd %d\n",out_evts[i].data.fd);
                        if((len = read(out_evts[i].data.fd,buf,BUFSIZ-1)) == -1){
                            perror("read err");
                            //return 1;
                        }
                        if(0 == len){
                            printf("close %d\n",out_evts[i].data.fd);
                            close(out_evts[i].data.fd);
                            epoll_ctl(epoll_fd,EPOLL_CTL_DEL,out_evts[i].data.fd,out_evts+i);
                            continue;
                        }
                        printf("server recv:%s\n",buf);
                        
                        int fd = open(buf,O_RDONLY);
                        if(-1 == fd){
                            perror("open file err");
                        }
                        struct stat file_stat;
                        fstat(fd,&file_stat);
                        if(-1 == sendfile(out_evts[i].data.fd,fd,NULL,file_stat.st_size)){
                            perror("sendfile err");
                        }
                        printf("server send file %s ok\n",buf);
                        close(fd);
                }
            }
        }
        
        close(epoll_fd);
        close(listenfd);
    }
    

    thread_max_size.c:用于检测计算机最大可执行线程的数量;

    #include <stdio.h>
    #include <pthread.h>
    
    void* test(void*arg){
        pause();
        //for(;;){}
    }
    
    int main(int argc,char* argv[]){
        pthread_t tid;
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        size_t stack_size = 8192*1024;
        pthread_attr_setstacksize(&attr,stack_size);
        pthread_attr_getstacksize(&attr,&stack_size);
        printf("thread stack size:%dk\n",stack_size/1024);
    
    
        size_t cnt = 0;
        for(;;){
            if(0 != pthread_create(&tid,&attr,test,NULL)){
                printf("max thread count:%d\n",cnt);
                break;  
            }
            cnt++;
        }
        pthread_attr_destroy(&attr);    
    }
    

    gethostbyname.c

    #include <stdio.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    
    int main(int argc,char** argv){
    
        struct hostent* host = gethostbyname(argv[1]);
        if(NULL == host){
            herror("gethostbyname err");
            return 1;
        }
        printf("hostname:%s\n",host->h_name);
        printf("aliases:");
        while(*host->h_aliases != NULL){
            printf("%s ",*host->h_aliases);
            host->h_aliases++;
        }
        printf("\n");
        printf("addrtype:%s\n",host->h_addrtype == AF_INET?"AF_INET":"AF_INET6");
        printf("length:%d\n",host->h_length);
        printf("addrlist:");
        while(*host->h_addr_list != NULL){
            //struct in_addr addr;
            //memcpy(&addr,*host->h_addr_list,host->h_length);
            //printf("%s ",inet_ntoa(addr));
            printf("%s ",inet_ntoa(*(struct in_addr*)*host->h_addr_list));
            host->h_addr_list++;
        }
    }
    

    ::

    相关文章

      网友评论

          本文标题:Linux-C-8-IO复用

          本文链接:https://www.haomeiwen.com/subject/ztewqxtx.html