Linux-C-8-IO復用

概念

IO復用:用于表示多個網(wǎng)絡鏈接復用一個IO線程专肪,具有開銷小的優(yōu)點拇厢,但是同樣的編程的復雜度就會比較高椭岩;

IO復用使用的幾個函數(shù)

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

maxfd:表示需要監(jiān)視的最大文件描述符值+1冯事;
rdset:需要檢測的刻度文件描述符集合宿接;
wrset:需要檢測的可寫文件描述符集合赘淮;
exset:需要檢測的異常文件描述符集合;
timeout:超時時間
返回值:-1表示出錯睦霎,0表示超時梢卸,>0表示獲取到的數(shù)據(jù);
同時還需要掌握的幾個函數(shù)包括:
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:是一個常數(shù)值表示的是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、需要修改傳入的參數(shù)數(shù)組碑幅;
2戴陡、不能夠確切指定有數(shù)據(jù)的socket;
3沟涨、只能夠監(jiān)視FD_SETSIZE數(shù)目個連接恤批;
4、線程不安全裹赴;

Poll模式

Poll模式具備的優(yōu)點:
1喜庞、不需要修改傳入的參數(shù)數(shù)組
2、可以監(jiān)視任意個連接棋返,可以通過cat /proc/sys/file-max進行查看
缺點:
1延都、不能夠確切的指定有數(shù)據(jù)的socket
2、線程不安全
poll模型需要使用的函數(shù)是int poll(struct pollfd *fdarray,usigned long nfds,int timeout);

struct pollfd *fdarray {
          fd:表示文件描述符號
          struct profile{
                    events:表示監(jiān)視的事件睛竣;
                    revents:表示實際發(fā)生的事件晰房;
          };
};

對于events支持的選項有:
?輸入:POLLRDNOPM:表示普通數(shù)據(jù);POLLRDBAND:優(yōu)先級帶數(shù)據(jù)射沟;POLLIN:普通或者優(yōu)先級帶數(shù)據(jù)嫉你;
?輸出:POLLWRNOPM:表示普通數(shù)據(jù);POLLWRBAND:優(yōu)先級帶數(shù)據(jù)躏惋;POLLOUT:普通或者優(yōu)先級帶數(shù)據(jù);
對于revents支持的選項包括:
?輸入:POLLRDNOPM:普通數(shù)據(jù)嚷辅;POLLRDBAND:優(yōu)先級帶數(shù)據(jù)簿姨;POLLIN:普通或者優(yōu)先級帶數(shù)據(jù);
?輸出:POLLWRNORW:普通數(shù)據(jù);POLLWRBAND:優(yōu)先級帶數(shù)據(jù)扁位;POOLLOUT:普通或者優(yōu)先級帶數(shù)據(jù)准潭;
?錯誤:POLLERR:發(fā)生錯誤;POLLHUP:發(fā)生掛起域仇;POLLNVAL:描述符非法刑然;

No 常量 events revents 說明
1 POLLIN OK OK 普通或者優(yōu)先級帶數(shù)據(jù)可讀;
2 POLLRDNORM OK OK 普通數(shù)據(jù)可讀
3 POLLRDBAND OK OK 優(yōu)先級帶數(shù)據(jù)可讀
4 POLLPRI OK OK 高優(yōu)先級數(shù)據(jù)可讀
5 POLLOUT OK OK 普通數(shù)據(jù)可寫
6 POLLWRNORM OK OK 普通數(shù)據(jù)可寫
7 POLLWRBAND OK OK 優(yōu)先級帶數(shù)據(jù)可寫
8 POLLERR NG OK 發(fā)生錯誤
9 POLLHUP NG OK 發(fā)生掛起
10 POLLNVAL NG OK 描述字不是一個打開的文件

其余的參數(shù)的含義
?nfds:表示數(shù)組元素的個數(shù)暇务;
?timeout泼掠;用于定義等待的時間;INFTIM:表示永久等待垦细;0:表示立即返回择镇;>0:表示等待描述;
?返回值0:表示超時括改;-1:表示出錯腻豌;正數(shù):表示就緒的描述符的個數(shù);
普通數(shù)據(jù):表示的含義是正規(guī)的TCP數(shù)據(jù)以及所有的UDP數(shù)據(jù)嘱能;優(yōu)先級帶數(shù)據(jù):表示TCP帶外的數(shù)據(jù)吝梅;

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模型

優(yōu)點:能夠確切地指定有數(shù)據(jù)的socket,并且線程是安全的惹骂;

Epoll模型的創(chuàng)建

使用函數(shù)int eploo_create(int size)來進行創(chuàng)建苏携,size用于指定監(jiān)聽的數(shù)目,返回值通常是文件描述符析苫,在/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 表示對應的文件描述符有緊急的數(shù)據(jù)可讀
EPOLLERR 表示對應文件描述符發(fā)生錯誤
EPOLLHUP 表示對應的文件描述符被掛斷
EPOLLET 表示對應的文件描述符設定為edge模式

使用函數(shù)int epoll_ctl(int epfd,int op,int fd, struct epoll_event *event);來進行epoll模型的控制;
epfd:表示epoll文件描述符衩侥;
op:用于定義對于文件描述符的操作国旷,EPOLL_CTL_ADD:表示用于創(chuàng)建;EPOLL_CTL_MOD:表示用于修改某些類型茫死;EPOLL_CTL_DEL:表示用于刪除跪但;fd:表示相互關(guān)聯(lián)的文件描述符;event:表示指向epoll_event的指針峦萎;

Epoll_event 說明
EPOLLOUT 表示對應的文件描述符可寫
EPOLLPRI 表示對應的文件描述符有緊急的數(shù)據(jù)可讀
EPOLLERR 表示對應文件描述符發(fā)生錯誤
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:用于回傳待處理事件的數(shù)組;
maxevents:每次能夠處理的事件數(shù)详幽;
timeout:等待IO事件發(fā)生的超時值筛欢;-1表示永不超時浸锨;0表示立即返回;
返回值:正數(shù)表示發(fā)生事件數(shù)版姑;-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的數(shù)據(jù);
3表制、調(diào)用epoll_wait可以獲得管道讀者已經(jīng)就緒的文件句柄健爬;
4、管道讀者讀取1Kb的數(shù)據(jù)夫凸;
5浑劳、一次epoll_wait調(diào)用完成;
如果執(zhí)行的是ET模式夭拌,管道中剩余的1Kb數(shù)據(jù)就會被掛起魔熏,等待再次調(diào)用epoll_wait(),得不到管道讀者的文件句柄鸽扁,除非有新的數(shù)據(jù)寫入管道蒜绽,如果是LT模式,只要管道中有數(shù)據(jù)可讀桶现,每次調(diào)用epoll_wait()都會觸發(fā)躲雅;
還有一點區(qū)別就是設為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:用于檢測計算機最大可執(zhí)行線程的數(shù)量骡和;

#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++;
    }
}

::

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末相赁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子慰于,更是在濱河造成了極大的恐慌钮科,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件婆赠,死亡現(xiàn)場離奇詭異绵脯,居然都是意外死亡,警方通過查閱死者的電腦和手機休里,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評論 3 392
  • 文/潘曉璐 我一進店門蛆挫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妙黍,你說我怎么就攤上這事悴侵。” “怎么了拭嫁?”我有些...
    開封第一講書人閱讀 162,632評論 0 353
  • 文/不壞的土叔 我叫張陵可免,是天一觀的道長筒繁。 經(jīng)常有香客問我,道長巴元,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,180評論 1 292
  • 正文 為了忘掉前任驮宴,我火速辦了婚禮逮刨,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘堵泽。我一直安慰自己修己,他們只是感情好,可當我...
    茶點故事閱讀 67,198評論 6 388
  • 文/花漫 我一把揭開白布迎罗。 她就那樣靜靜地躺著睬愤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪纹安。 梳的紋絲不亂的頭發(fā)上尤辱,一...
    開封第一講書人閱讀 51,165評論 1 299
  • 那天,我揣著相機與錄音厢岂,去河邊找鬼光督。 笑死,一個胖子當著我的面吹牛塔粒,可吹牛的內(nèi)容都是我干的结借。 我是一名探鬼主播,決...
    沈念sama閱讀 40,052評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼卒茬,長吁一口氣:“原來是場噩夢啊……” “哼船老!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起圃酵,我...
    開封第一講書人閱讀 38,910評論 0 274
  • 序言:老撾萬榮一對情侶失蹤柳畔,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后辜昵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體荸镊,經(jīng)...
    沈念sama閱讀 45,324評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,542評論 2 332
  • 正文 我和宋清朗相戀三年堪置,在試婚紗的時候發(fā)現(xiàn)自己被綠了躬存。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,711評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡舀锨,死狀恐怖岭洲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情坎匿,我是刑警寧澤盾剩,帶...
    沈念sama閱讀 35,424評論 5 343
  • 正文 年R本政府宣布雷激,位于F島的核電站,受9級特大地震影響告私,放射性物質(zhì)發(fā)生泄漏屎暇。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,017評論 3 326
  • 文/蒙蒙 一驻粟、第九天 我趴在偏房一處隱蔽的房頂上張望根悼。 院中可真熱鬧,春花似錦蜀撑、人聲如沸挤巡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,668評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽矿卑。三九已至,卻和暖如春沃饶,著一層夾襖步出監(jiān)牢的瞬間母廷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,823評論 1 269
  • 我被黑心中介騙來泰國打工绍坝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留徘意,地道東北人。 一個月前我還...
    沈念sama閱讀 47,722評論 2 368
  • 正文 我出身青樓轩褐,卻偏偏與公主長得像椎咧,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子把介,可洞房花燭夜當晚...
    茶點故事閱讀 44,611評論 2 353

推薦閱讀更多精彩內(nèi)容