selec, poll, epoll实践

1 篇文章 0 订阅

poll例子

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <poll.h>
#define MAX 10
int start_up(sockaddr_in &addr){
    int socketi = socket(PF_INET, SOCK_STREAM, 0);
    if (socketi < 0) {
        std::cout << "socket error" << std::endl;
        return -1;
    }
    int flag = bind(socketi, (sockaddr*)&addr, sizeof(addr));
    if (flag < 0){
        std::cout << "bind error" << std::endl;
        return -1;
    }
    flag = listen(socketi, 5);
    if (flag < 0){
        std::cout << "listen error" << std::endl;
        return -1;
    }
    return socketi;
}

int start_poll(int socket) {
    char fd[MAX] = {0};
    struct pollfd pfd[MAX];
    pfd[0].fd = socket;
    pfd[0].events = POLLIN;
    for (int i = 1; i < MAX; i++) {
        pfd[i].fd = -1;
    }
    bool flag = true;
    int max = socket;
    char buf[MAX] = {0};
    while (true) {
        int timeout = 2000;
        if (!flag) {//这个flag是为了更新max
            max = 0;
            for (int i = 1; i < MAX; i++) {
                if (pfd[i].fd > MAX) {
                    max = pfd[i].fd;
                }
            }
        }
        int ready = poll(pfd, max + 1, timeout);//max是为了poll遍历循环用的,ready是表示有多少个描述符收到了消息
        if (pfd[0].revents & POLLIN) {
            if (max > MAX) {
            } else  {
                struct sockaddr_in client;
                socklen_t client_len = sizeof(client);
                int connfd = accept(socket, (struct sockaddr*)&client, &client_len);
                if (connfd < 0) {
                    std::cout << "connect error" << std::endl;
                    continue;
                }
                std::cout << "new connect is comming" << std::endl;
                for (int i = 1; i < MAX; i++) {
                    if (pfd[i].fd < 0) {
                        pfd[i].fd = connfd;
                        pfd[i].events = POLLIN;
                        max++;
                        break;
                    }
                }
            }
            if (--ready <= 0) {
                continue;
            }
        }
        for (int i = 1; i < MAX; i++) {
            if (pfd[i].fd < 0) {
                continue;
            }
            if (pfd[i].fd > 0 &&  (pfd[i].revents & (POLLIN|POLLERR))) {
                ssize_t size = read(pfd[i].fd, buf, 20);
                if (size < 0) {
                    if (errno == ECONNRESET) {//对方重启连接,还未建立连接;发送端已经断开连接,却仍调用send;对端关闭连接时,缓冲区有数据未读完,调用close(fd),连接并未关闭。因为close(fd)只是将描述符关闭,并未关闭tcp连接,关闭连接需要4次握手
                        close(pfd[i].fd);
                        pfd[i].fd = -1;
                        max--;
                    } else {
                        std::cout << "recv error" << std::endl;//其他错误
                    }
                    continue;
                } else if (size == 0) {//对方服务器关闭,例如发送了FIN
                    close(pfd[i].fd);
                    pfd[i].fd = -1;
                    max--;
                    continue;
                }
                buf[size-1] = '\0';
                std::cout << "client say: " << buf << std::endl;
            }
            if (--ready) {
                break;
            }
        }
    }

}

int main(int argc, char *argv[]){
    if (argc < 2) {
        std::cout << "usage: ./a.out 127.0.0.1 7801" << std::endl;
        return -1;
    }
    struct sockaddr_in addr;
    bzero(&addr, sizeof(addr));
    addr.sin_addr.s_addr = inet_addr(argv[1]);
    addr.sin_port = htons(atoi(argv[2]));
    addr.sin_family = PF_INET;
    int socket = start_up(addr);
    if (socket < 0) {
        std::cout << "socket error" << std::endl;
        return  -1;
    }
    start_poll(socket);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值