Linux poll服务端

Linux poll服务端

源代码:pollServer.cpp

/*******************************************************************************
* pollServer.cpp
*
* Create on 2018-10-6
*   Author: yanxinchun
*
* g++ -o pollServer pollServer.cpp
*******************************************************************************/
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/poll.h>

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

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

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

void handle_sigchld(int sig)
{
    while(waitpid(-1, NULL, WNOHANG) > 0) ;
}

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

    /* 在一个进程停止或终止时,将SIGPIPE信号发送给其父进程,按系统默认将忽略此信号,
       如果父进程希望被告知其子系统的这种状态,则应捕捉此信号。*/
    signal(SIGCHLD, handle_sigchld);

    int listenfd = socket(PF_INET, SOCK_STREAM, 0);
    if(listenfd < 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 = htonl(INADDR_ANY);
    
    int on = 1;
    if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
        ERR_EXIT("setsockopt fail!");
    }
    
    if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) {
        ERR_EXIT("bind fail!");
    }
    
    if(listen(listenfd, SOMAXCONN) < 0) {
        ERR_EXIT("listen fail!");
    }

    struct sockaddr_in peeraddr;
    socklen_t peerlen = sizeof(peeraddr);
    int conn;
    
    PACKET_st recvbuf;
    int i;
    int maxi = 0;
    struct pollfd client[POLL_MAX_CN];
    for(i = 0; i < POLL_MAX_CN; ++i) {
        client[i].fd = -1;
    }
    
    int nready;
    client[0].fd = listenfd;
    client[0].events = POLLIN;
    while(1){
        nready = poll(client, maxi + 1, -1);
        if(nready == -1) {
            if(errno == EINTR) {
                continue;
            }
            ERR_EXIT("poll");
        }
        
        if(nready == 0) {
            //printf("nready=%d, continue\n", nready);
            continue;
        }
        
        if(client[0].revents & POLLIN) {
            printf("listen...\n");
            peerlen = sizeof(peeraddr);
            conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);
            if(conn == -1) {
                ERR_EXIT("accept fail!");
            }
            
            for(i = 0; i < POLL_MAX_CN; ++i) {
                if(client[i].fd < 0) {
                    client[i].fd = conn;
                    if(i > maxi) {
                        maxi = i;
                    }
                    break;
                }
            }
            
            if(i == POLL_MAX_CN) {
                fprintf(stderr, "too many clients\n");
                exit(EXIT_FAILURE); 
            }
            
            printf("accept ip=%s, port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));
            //printf("maxi=%d, i=%d\n", maxi, i);
            
            client[i].events = POLLIN;
            
            if(--nready <= 0) {
                //printf("nready=%d, continue\n", nready);
                continue;
            }
        }
        
        for(i = 1; i <= maxi; ++i) {
            conn = client[i].fd;
            if(conn == -1) {
                continue;
            }
            
            if(client[i].revents & POLLIN) {
                int n;
                int ret;
                memset(&recvbuf, 0, sizeof(recvbuf));
                ret = read(conn, &recvbuf.len, 4);
                if(ret == -1) {
                    ERR_EXIT("ser read fail 11!");
                }else if(ret < 4) {
                    printf("client close, ret = %d\n", ret);
                    client[i].fd = -1;
                    shutdown(conn, SHUT_WR);
                } else {
                    n = ntohl(recvbuf.len);
                    ret = read(conn, &recvbuf.buf, n);
                    if(ret == -1) {
                        ERR_EXIT("ser read fail 22!");
                    } else if(ret < n) {
                        printf("client close 22, ret = %d\n", ret);
                        client[i].fd = -1;
                        shutdown(conn, SHUT_WR);
                    }
                    
                    printf("recv: len=%d, ctx=%s", ntohl(recvbuf.len), recvbuf.buf);
                    //fputs(recvbuf.buf, stdout);
                    
                    printf("reply: len=%d, ctx=%s\n", ntohl(recvbuf.len), recvbuf.buf);
                    write(conn, &recvbuf, 4 + n);
                }
                
                if(--nready <= 0) {
                    break;
                }
            }
        }
    }
    
    close(listenfd);
    return 0;
}

编译运行:

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

猜你喜欢

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