Linux epoll客户端

Linux epoll客户端

源代码:epollClient.cpp

/*******************************************************
* epollClient.cpp
*
* Create on 2018-10-6
*   Author: yanxinchun
*
* g++ -o epollClient epollClient.cpp
*******************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/select.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <vector>
#include <algorithm>
#include <assert.h>

#define POLL_MAX_CN (1024)
#define ERR_EXIT(m) \
    do {            \
        perror(m);    \
        exit(EXIT_FAILURE);    \
    } while(0)

typedef std::vector<struct epoll_event>    EventList;

typedef struct _packet_st {
    int len;
    char buf[1024];
} PACKET_st;

ssize_t readn(int fd, void *buf, size_t count)
{
    size_t nleft = count;
    ssize_t nread;
    char *bufp = (char*)buf;
    
    while(nleft > 0){
        if(nread = read(fd, bufp, nleft) < 0) {
            if(errno == EINTR) {
                continue;
            }
            return -1;
        }else if(nread == 0) {
            return count - nleft;
        }
        
        bufp += nread;
        nleft -= nread;
    }
    
    return count;
}

ssize_t writen(int fd, const void *buf, size_t count)
{
    size_t nleft = count;
    ssize_t nwritten;
    char *bufp = (char*)buf;
    
    while(nleft > 0) {
        if(nwritten = write(fd, bufp, nleft) < 0) {
            if(errno == EINTR) {
                continue;
            }
            return -1;
        }else if(nwritten == 0) {
            continue;
        }
        
        bufp += nwritten;
        nleft -= nwritten;
    }
    
    return count;
}

int getlocalip(char *ip) {
    char host[100] = {0};
    if(gethostname(host, sizeof(host)) < 0) {
        return -1;
    }

    struct hostent* hp;
    if((hp = gethostbyname(host)) == NULL) {
        return -1;
    }
    
    strcpy(ip, inet_ntoa(*(struct in_addr*)hp->h_addr_list[0]));
    //int i = 0;
    //while(hp->h_addr_list[i] != NULL) {
    //    printf("%s\n", inet_ntoa(*(struct in_addr*)hp->h_addr_list[i]));
    //    ++i;
    //}
    return 0;
}

/**
 *  * * activate_nonblock - 设置I/O为非阻塞模式
 *   * * @fd: 文件描述符
 *    * */
void activate_nonblock(int fd)
{
    int ret;
    int flags = fcntl(fd, F_GETFL);
    if(flags == -1) {
         ERR_EXIT("fcntl fail!");
    }
    
    flags |= O_NONBLOCK;
    ret = fcntl(fd, F_SETFL, flags);
    if(ret == -1) {
         ERR_EXIT("fcntl fail!");
    }
}

/**
 *  * * deactivate_nonblock - 设置I/O为阻塞模式
 *   * * @fd: 文件描述符
 *    * */
void deactivate_nonblock(int fd)
{
    int ret;
    int flags = fcntl(fd, F_GETFL);
    if(flags == -1) {
         ERR_EXIT("fcntl fail!");
    }
    
    flags &= ~O_NONBLOCK;
    ret = fcntl(fd, F_SETFL, flags);
    if(ret == -1) {
         ERR_EXIT("fcntl fail!");
    }
}

void handle_sigpipe(int sig)
{
    printf("[sigpipe] recv a sig=%d\n", sig);
}

int main()
{
    //往一个已经关闭的socket写入数据会触发SIGPIPE
    signal(SIGPIPE, handle_sigpipe);

    int sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sock < 0) {
        ERR_EXIT("socket fail!");
    }
    
    struct sockaddr_in servaddr;
    memset(&servaddr, 0, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(8914);
    servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

    // connect
    if(connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
        ERR_EXIT("connect fail!");
    }

    /*
    printf("client connect success\n");
    char ip[32] = {0};
    getlocalip(ip);
    printf("local ip: %s\n", ip);
    */
    
    struct sockaddr_in localaddr;
    socklen_t addrlen = sizeof(localaddr);
    if(getsockname(sock, (struct sockaddr*)&localaddr, &addrlen) < 0){
        ERR_EXIT("getsockname fail!");
    }
    
    printf("local ip=%s, port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));

    PACKET_st recvbuf;
    PACKET_st sendbuf;
    memset(&recvbuf, 0, sizeof(recvbuf));
    memset(&sendbuf, 0, sizeof(sendbuf));

    std::vector<int> clients;
    int epollfd = epoll_create1(EPOLL_CLOEXEC); // 用于设置改描述符的close-on-exec(FD_CLOEXEC)标志
  
    struct epoll_event event;
    int fd_stdin = fileno(stdin);
    event.data.fd = fd_stdin;
    event.events = EPOLLIN | EPOLLET;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd_stdin, &event);
    
    event.data.fd = sock;
    event.events = EPOLLIN | EPOLLET;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, sock, &event);

    EventList events(4);
    int i;
    int nready = 0;
    while(1){
        nready = epoll_wait(epollfd, &*events.begin(), static_cast<int>(events.size()), -1);
        if(nready == -1) {
            if(errno == EINTR) {
                continue;
            }
            ERR_EXIT("epoll_wait fail!");
        }
        
        if(nready == 0) {
            continue;
        }
        
        if((size_t)nready == events.size()) {
            events.resize(events.size() * 2);
        }
        
        for(i = 0; i < nready; ++i) {
            if(events[i].data.fd == fd_stdin) {
                //printf("stdin ......\n");
                if(fgets(sendbuf.buf, sizeof(sendbuf.buf), stdin) == NULL){
                    printf("stdin is null ...\n");
                    shutdown(sock, SHUT_WR);
                    event = events[i];
                    epoll_ctl(epollfd, EPOLL_CTL_DEL, fd_stdin, &event);
                } else {
                    int len = strlen(sendbuf.buf);
                    sendbuf.len = htonl(len);
                    write(sock, &sendbuf, 4 + len);
                    memset(&sendbuf, 0, sizeof(sendbuf));
                }
            } else if(events[i].data.fd == sock) {
                if(sock < 0){
                    continue;
                }
                
                //printf("sock in ......\n");
                int ret = read(sock, &recvbuf.len, 4);
                if(ret == -1) {
                    ERR_EXIT("cli read fail!");
                } else if(ret < 4) {
                    printf("server close 1.\n");
                    shutdown(sock, SHUT_WR);
                    event = events[i];
                    epoll_ctl(epollfd, EPOLL_CTL_DEL, sock, &event);
                    return 0;
                }
                
                int n = ntohl(recvbuf.len);
                ret = read(sock, &recvbuf.buf, n);
                if(ret == -1) {
                    ERR_EXIT("cli read fail!");
                } else if(ret < n) {
                    printf("server close 2\n");
                    shutdown(sock, SHUT_WR);
                    event = events[i];
                    epoll_ctl(epollfd, EPOLL_CTL_DEL, sock, &event);
                    return 0;
                }
            
                printf("recv: len=%d, ctx=%s", ntohl(recvbuf.len), recvbuf.buf);
                //fputs(recvbuf.buf, stdout);
				
                memset(&recvbuf, 0, sizeof(recvbuf));
            }
        }
    }

    return 0;
}

编译运行:

[root@QIANZI-BASE keke]# g++ -o epollClient epollClient.cpp

猜你喜欢

转载自blog.csdn.net/qian_feifei/article/details/83002713