socket创建失败_linux下socket采用epoll编程demo

首先,需要调用epoll_create创建epoll; 此后我们就可以进行socket/bind/listen; 然后调用epoll_ctl进行注册; 接下来,就可以通过一个while(1)循环调用epoll_wait来等待事件的发生; 然后循环查看接收到的事件并进行处理; 1)如果事件是sever的socketfd我们就要进行accept,并且把接收到client的socketfd加入到要监听的事件中; 2)如果在监听过程中,需要修改操作方式(读/写),可以调用epoll_ctl来重新修改; 3)如果监听到某一个客户端关闭,那么我就需要再次调用epoll_ctl把它从epoll监听事件中删除。

7fefc33e4caad4e77eda6cb606d85104.png

epoll的结构体

typedef union epoll_data {     void        *ptr;     int          fd;     uint32_t     u32;     uint64_t     u64; } epoll_data_t;  struct epoll_event {     uint32_t     events;      /* Epoll events */     epoll_data_t data;        /* User data variable */ };
#include #include #include #include #include #include #include #include #include #define SERV_PORT  8802int main(){    int i,flag;    int sockfd,clntfd,newfd;    int epfd,nfds;    ssize_t n;    char buffer[1024];    int s = sizeof(struct sockaddr);    struct sockaddr_in serv_addr;    struct sockaddr_in clnt_addr;    //定义epoll数据结构    struct epoll_event ev,events[20];    epfd = epoll_create(256);    //创建socket,并初始化事件ev    sockfd = socket(AF_INET, SOCK_STREAM, 0);    if (sockfd < 0) {        perror("socket error!");        return -1;    }    ev.data.fd = sockfd;    ev.events = EPOLLIN|EPOLLET;    //注册epoll事件    flag = epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, &ev);    if (flag < 0) {        perror("epoll_ctl error!");        return -1;    }    bzero(&serv_addr, sizeof(serv_addr));    serv_addr.sin_family = AF_INET;    serv_addr.sin_port = htons(SERV_PORT);    serv_addr.sin_addr.s_addr = htonl( INADDR_ANY );    flag = bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(struct sockaddr));    if (flag < 0) {        perror("bind error!");        return -1;    }    printf("bind");    flag = listen(sockfd, 20);    if (flag < 0) {        perror("listen error!");        return -1;    }    printf("listen");    //开始循环    while (1) {        //等待事件发生,返回请求数目        nfds = epoll_wait(epfd, events, 20, 500);        //一次处理请求        for (i = 0; i < nfds; ++i) {            if (events[i].data.fd == sockfd){                clntfd = accept(sockfd, (struct sockaddr*)&clnt_addr,(unsigned int*)&s);                if (clntfd < 0) {                    perror("accept error");                    continue;                }                printf("accept");                char *str = inet_ntoa(clnt_addr.sin_addr);                printf("accepnt the client ip : %s",str);                //设置文件标识符,设置操作属性:写操作                ev.data.fd = clntfd;                ev.events = EPOLLOUT | EPOLLET;                //向创建的的epoll进行注册写操作                epoll_ctl(epfd, EPOLL_CTL_ADD, clntfd, &ev);            } else if (events[i].events & EPOLLOUT) {                printf("EPOLLOUT");                if ((newfd = events[i].data.fd) < 0)                    continue;                bzero(buffer,sizeof(buffer));                strcpy(buffer,"welcome to myserver!");                flag = send(newfd, buffer, 1024, 0);                if (flag < 0) {                    perror("send error");                    continue;                }                //修改操作为读操作                ev.data.fd = clntfd;                ev.events = EPOLLIN | EPOLLET;                epoll_ctl(epfd, EPOLL_CTL_MOD, newfd, &ev);            } else if (events[i].events & EPOLLIN) {                printf("EPOLLIN");                bzero(buffer,sizeof(buffer));                if ((newfd = events[i].data.fd) < 0)                    continue;                if ((n = read(newfd, buffer, 1024)) < 0) {                    if (errno == ECONNRESET){                        close(newfd);                        events[i].data.fd = -1;                        printf("errno ECONRESET!");                    } else {                        perror("readbuffer error!");                    }                } else if (n == 0) {//表示客户端已经关闭                    close(newfd);                    events[i].data.fd = -1;                    printf("n为0");                }                if (buffer[0] != '0')                    printf("have read: %s", buffer);            }        }    }    close(sockfd);    return 0;}

优化

#include #include #include #include #include #include #include #include #include #define SERV_PORT   8802#define MAX_EVENTS  20int main(){    int listen_fd = socket(AF_INET, SOCK_STREAM, 0);    //若成功则返回非负描述符,若失败则返回-1,第一个参数指明协议族(IPv4或IPv6等)    if (listen_fd < 0) {                                //第二个参数指明套接字类型,字节流套接字(SOCK_STREAM)和数据报套接字(SOCK_DGRAM)        perror("socket error!");        return -1;    }    int epfd = epoll_create(256);  //参数会被忽略,但是要大于0,                                    //若成功返回一个大于 0 的值,表示 epoll 实例;若返回 -1 表示出错    //针对监听的sockfd,创建epollevent    struct epoll_event event;    event.data.fd = listen_fd;    event.events = EPOLLIN | EPOLLET;    //注册epoll事件    int flag = epoll_ctl(epfd, EPOLL_CTL_ADD, listen_fd, &event);  //int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);    if (flag < 0) {                                                //成功返回0,出错返回-1        perror("epoll_ctl error!");        return -1;    }        if (bindAndListenFd(listen_fd) < 0)        return -1;    //定义epoll数据结构    struct epoll_event events[MAX_EVENTS];  //可以使用vector,参见muduo源码中的使用    while (1) {        //等待事件发生,返回请求数目        int nfds = epoll_wait(epfd, events, MAX_EVENTS, 500);   //maxevents: 返回的events的最大个数,如果最大个数大于实际触发的个数,则下次epoll_wait的时候仍然可以返回                                                                //int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);                                                                //成功返回的是一个大于 0 的数,表示事件的个数;返回 0 表示的是超时时间到;若出错返回 -1.        for (int i = 0; i < nfds; ++i) {                              if (events[i].data.fd == listen_fd) {                struct sockaddr_in client_addr;                int client_fd = accept(listen_fd, (struct sockaddr*)&client_addr, sizeof(client_addr));  //若成功则为非负描述符,若出错则返回-1                if (client_fd < 0) {                    perror("accept error");                    continue;                }                char *str = inet_ntoa(client_addr.sin_addr);                printf("accept the client ip : %s",str);                onRecvNewConnect(epfd, client_fd);            } else if (events[i].events & EPOLLOUT) {                int sockfd = events[i].data.fd;                if (sockfd < 0)                    continue;                onWriteFd(epfd, sockfd);                            } else if (events[i].events & EPOLLIN) {                int sockfd = events[i].data.fd;                if (sockfd < 0)                    continue;                if (onReadFd(epfd, sockfd) < 0) {                    events[i].data.fd = -1;                }            }        }    }    close(sockfd);    return 0;}int bindAndListenFd(int sockfd) {    ::fcntl(sockfd, F_SETFL, O_NONBLOCK);                    //设置非阻塞模式    struct sockaddr_in serv_addr;    bzero(&serv_addr, sizeof(serv_addr));                    //void bzero(void *dest, size_t nbytes);    serv_addr.sin_family = AF_INET;                          //类似void *memset(void *dest, int c, size_t len);    serv_addr.sin_port = htons(SERV_PORT);                   //本地端口号转化为网络端口号 host to network short    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);           //INADDR_ANY代表本机所有的IP地址  host to network long    int flag = bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));   //成功返回0,出错返回-1    if (flag < 0) {        perror("bind error!");        return -1;    }    flag = listen(sockfd, 20);                         //成功返回0,出错返回-1    if (flag < 0) {        perror("listen error!");        return -1;    }    return 0;}void onRecvNewConnect(int epfd, int clientfd) {    ::fcntl(sockfd, F_SETFL, O_NONBLOCK);                //设置非阻塞模式    //设置文件标识符,设置操作属性:写操作    struct epoll_event ev_client;    ev_client.data.fd = clintfd;    ev_client.events = EPOLLOUT | EPOLLET;    //向创建的的epoll进行注册写操作    epoll_ctl(epfd, EPOLL_CTL_ADD, clientfd, &ev_client);}void onWriteFd(int epfd, int sockfd) {    char buffer[1024];    bzero(buffer, sizeof(buffer));    strcpy(buffer, "welcome to myserver!");    int flag = send(sockfd, buffer, 1024, 0);    if (flag < 0) {        perror("send error");        return;    }    //修改操作为读操作    struct epoll_event ev_client;    ev_client.data.fd = sockfd;    ev_client.events = EPOLLIN | EPOLLET;    epoll_ctl(epfd, EPOLL_CTL_MOD, sockfd, &ev_client);}int onReadFd(int epfd, int sockfd) {    char buffer[1024];    bzero(buffer, sizeof(buffer));    int n = read(sockfd, buffer, 1024);    if (n < 0) {        if (errno == ECONNRESET) {            close(sockfd);            printf("errno ECONRESET!");            return -1;        } else {            perror("readbuffer error!");        }    } else if (n == 0) {      //表示客户端已经关闭        close(sockfd);        printf("n为0");        return -1;    }    if (buffer[0] != '0')        printf("have read: %s", buffer);    return 0;}


文章分析视频讲解,epoll网络io视频链接:网络io,epoll实战揭秘

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值