Linux-C-8-IO复用

概念

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

::

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容