最简单的socket套接字编程(2)–poll()和epoll()

最简单的socket套接字编程(2)–poll()和epoll()

作者:gaopenghigh ,转载请注明出处。 (原文地址)


本文主要介绍了使用poll()epoll()在UNIX环境下socket网络编程的主要步骤,实现 了一个简单的 服务器和客户端代码实例,实现了一个网络服务,该服务接受一个字符串的命令,执行该命 令,并且把结 果返回给客户端。

关于socket网络编程的基本概念以及多进程、多线程的网络服务器的原理和实例,参考 最简单的socket套接字编程

关于poll()epoll()的介绍和用法,参考 一步步理解Linux之IO(2)–高级IO

Client

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>



#define BUFLEN 256



void error(const char *msg)

{

    perror(msg);

    exit(0);

}



int main(int argc, char *argv[])

{

    int sockfd, portno, n;

    struct sockaddr_in serv_addr;

    struct hostent *server;



    char buffer[BUFLEN];

    if (argc < 3) {

       fprintf(stderr,"usage %s hostname port\n", argv[0]);

       exit(0);

    }

    portno = atoi(argv[2]);



    if ((server = gethostbyname(argv[1])) == NULL) {

        fprintf(stderr,"ERROR, no such host\n");

        exit(0);

    }

    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;

    bcopy((char *)server->h_addr,

          (char *)&serv_addr.sin_addr.s_addr,

          server->h_length);

    serv_addr.sin_port = htons(portno);



    while (1) {

        if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)

            error("ERROR opening socket");



        if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0)

            error("ERROR connecting");

        printf(">>> ");

        bzero(buffer, BUFLEN);

        fgets(buffer, BUFLEN, stdin);

        if((n = send(sockfd, buffer, strlen(buffer), 0)) <= 0)

             error("ERROR writing to socket");

        bzero(buffer, BUFLEN);

        while ((n = recv(sockfd, buffer, BUFLEN, 0)) > 0) {

            printf("%s",buffer);

        }

    }

    return 0;

}

poll()实现的server

/* A simple server to run system commands use poll */

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <signal.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <poll.h>

#include <fcntl.h>



#define PORTNO 4444

#define BACKLOG 10

#define BUFLEN 256

#define MAXCONN 100

#define TRUE 1

#define FALSE 0



void error(const char *msg) {

    perror(msg);

}



/*

 * function really do the service

 * run cmd geted from client and return the output to client

 */

void serve(struct pollfd *pfd) {

    int n;

    char buffer[BUFLEN];

    FILE *fp;



    bzero(buffer, BUFLEN);

    printf("in serve ,fd=%d\n", pfd->fd);

    if (pfd->revents & POLLIN) {                /* read */

        if ((n = read(pfd->fd, buffer, BUFLEN)) < 0)

            printf("ERROR reading from socket : %d", n);

        printf("CMD : %s\n",buffer);

        if ((fp = popen(buffer, "r")) == NULL)

            error("ERROR when popen");

        while (fgets(buffer, BUFLEN, fp) != NULL) {

            if (send(pfd->fd, buffer, BUFLEN, 0) == -1)

                error("send ERROR");

        }

        printf("serve end, closing %d\n", pfd->fd);

        close(pfd->fd);

        pfd->fd = -1;

        pclose(fp);

    }

}



/*

 * Init listen socket and bind it to addr, return the listen socket

 */

int init_server() {

    int sockfd;

    struct sockaddr_in serv_addr;



    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

        error("ERROR opening socket");

        exit(1);

    }



    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;

    serv_addr.sin_addr.s_addr = INADDR_ANY;

    serv_addr.sin_port = htons(PORTNO);



    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {

        error("ERROR on binding");

        exit(1);

    }



    return sockfd;

}



/*

 * set fd nonblocking, success return 0, fail return -1

 */

int setnonblocking(int fd) {

    if (fd > 0) {

        int flags = fcntl(fd, F_GETFL, 0);

        flags = flags|O_NONBLOCK;

        if (fcntl(fd, F_SETFL, flags) == 0) {

            printf("setnonblocking success!\n");

            return 0;

        }

    }

    return -1;

}



void printfd(struct pollfd array[], int n) {

    int i;

    printf("array = ");

    for(i = 0; i < n; i++)

        printf("[%d]:%d ", i, array[i].fd);

    printf("\n");

}



/*

 * Use poll() to serve for every connection

 */

int main(int argc, char *argv[]) {

    int endserver = FALSE;

    int listen_sock, conn_sock, pos, i, j;

    struct sockaddr_in cli_addr;

    socklen_t clilen = sizeof(cli_addr);



    /* INIT pollfd structures */

    struct pollfd allfds[MAXCONN];

    printf("sizeof(allfds)=%d\n", (int)sizeof(allfds));

    memset(allfds, 0, sizeof(allfds));

    int nfds = 0;    /* number of fds in allfds */

    int currentsize; /* current size of allfds */

    int poll_result;



    /* init listen socket, bind, listen */

    listen_sock = init_server();

    setnonblocking(listen_sock);

    listen(listen_sock, BACKLOG);



    /* add listen_socket to allfds array */

    allfds[0].fd = listen_sock;

    allfds[0].events = POLLIN;

    nfds++;





    while (endserver == FALSE) {

        printfd(allfds, nfds);

        printf("nfds=%d\n", nfds);

        /* wait for events on sockets, timeout = -1 means waite forever */

        poll_result = poll(allfds, nfds, -1);

        if (poll_result == -1) {

            error("poll ERROR");

            break;

        } else if (poll_result == 0) {

            printf("poll round timeout, enther another poll...\n");

            continue;

        }

        /*******************************************************************/

        /* One or more descriptors are readable                            */

        /*******************************************************************/

        currentsize = nfds;

        printf("correntsize=%d\n", currentsize);

        for (pos = 0; pos < currentsize; pos++) {

            if (allfds[pos].revents & POLLIN &&

                    allfds[pos].fd == listen_sock) {  /* listen socket */

                printf("event on listen sock\n");

                /* Accept all incomming connections */

                do {

                    printf("listen_sock=%d\n", listen_sock);

                    conn_sock = accept(listen_sock,

                                   (struct sockaddr *)&cli_addr, &clilen);

                    if (conn_sock < 0)

                        continue;

                    setnonblocking(conn_sock);

                    if (nfds >= MAXCONN) {

                        error("nfds >= MAXCONN");

                        break;

                    }

                    allfds[nfds].fd = conn_sock;

                    allfds[nfds].events = POLLIN;

                    nfds++;

                } while(conn_sock != -1);



            /* regular socket */

            } else {

                serve(&allfds[pos]);

            }



            /* comparess allfds, delete the items which fd = -1 */

            for (i = 0; i < nfds; i++) {

                if (allfds[i].fd == -1) {

                    for (j = i; j < nfds; j++) {

                        allfds[j] = allfds[j+1];

                    }

                    nfds--;

                    i--;

                }

            }

        }



    }



    /* end server */

    for (i = 0; i < nfds; i++) {

        if (allfds[i].fd >= 0)

            close(allfds[i].fd);

    }



    return 0;



}

epoll()实现的server

/* A simple server to run system commands use poll */

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <signal.h>

#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <sys/epoll.h>

#include <fcntl.h>



#define PORTNO 4444

#define BACKLOG 10

#define BUFLEN 256

#define MAXCONN 100

#define TRUE 1

#define FALSE 0



void error(const char *msg) {

    perror(msg);

}



/*

 * function really do the service

 * run cmd geted from client and return the output to client

 */

void serve(int fd) {

    int n;

    char buffer[BUFLEN];

    FILE *fp;



    bzero(buffer, BUFLEN);

    printf("in serve ,fd=%d\n", fd);

    if ((n = read(fd, buffer, BUFLEN)) < 0)

        printf("ERROR reading from socket : %d", n);

    printf("CMD : %s\n",buffer);

    if ((fp = popen(buffer, "r")) == NULL)

        error("ERROR when popen");

    while (fgets(buffer, BUFLEN, fp) != NULL) {

        if (send(fd, buffer, BUFLEN, 0) == -1)

            error("send ERROR");

    }

    printf("serve end, closing %d\n", fd);

    pclose(fp);

}



/*

 * Init listen socket and bind it to addr, return the listen socket

 */

int init_server() {

    int sockfd;

    struct sockaddr_in serv_addr;



    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {

        error("ERROR opening socket");

        exit(1);

    }



    bzero((char *) &serv_addr, sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;

    serv_addr.sin_addr.s_addr = INADDR_ANY;

    serv_addr.sin_port = htons(PORTNO);



    if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {

        error("ERROR on binding");

        exit(1);

    }



    return sockfd;

}



/*

 * set fd nonblocking, success return 0, fail return -1

 */

int setnonblocking(int fd) {

    if (fd > 0) {

        int flags = fcntl(fd, F_GETFL, 0);

        flags = flags|O_NONBLOCK;

        if (fcntl(fd, F_SETFL, flags) == 0) {

            printf("setnonblocking success!\n");

            return 0;

        }

    }

    return -1;

}





/*

 * Use poll() to serve for every connection

 */

int main(int argc, char *argv[]) {

    int endserver = FALSE;

    int listen_sock, conn_sock, n;

    struct sockaddr_in cli_addr;

    socklen_t clilen = sizeof(cli_addr);



    /* INIT pollfd structures */

    struct epoll_event ev, events[MAXCONN];

    int nfds;

    int epollfd = epoll_create(10);

    if (epollfd == -1) {

        printf("epoll_create error\n");

        exit(1);

    }



    /* init listen socket, bind, listen */

    listen_sock = init_server();

    setnonblocking(listen_sock);

    listen(listen_sock, BACKLOG);



    /* register listen_sock to epollfd */

    ev.events = EPOLLIN;

    ev.data.fd = listen_sock;

    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {

        printf("ERROR: epoll_ctl\n");

        exit(1);

    }



    while (endserver == FALSE) {

        nfds = epoll_wait(epollfd, events, MAXCONN, -1);

        if (nfds == -1) {

            printf("epoll_wait ERROR\n");

            exit(1);

        }



        for (n = 0; n < nfds; n++) {

            if (events[n].data.fd == listen_sock) { /* listen socket */

                do {

                    printf("listen_sock=%d\n", listen_sock);

                    conn_sock = accept(listen_sock,

                                   (struct sockaddr *)&cli_addr, &clilen);

                    if (conn_sock < 0)

                        continue;

                    setnonblocking(conn_sock);

                    ev.events = EPOLLIN|EPOLLET;

                    ev.data.fd = conn_sock;

                    if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev)

                            == -1) {

                        printf("epoll_ctl for conn_sock ERROR\n");

                        exit(1);

                    }

                } while(conn_sock != -1);

            } else { /* regular connection */

                serve(events[n].data.fd);

                ev.events = EPOLLIN|EPOLLET;

                ev.data.fd = conn_sock;

                if (epoll_ctl(epollfd, EPOLL_CTL_DEL, events[n].data.fd, &ev)

                        == -1) {

                    printf("epoll_ctl DEL ERROR\n");

                    exit(1);

                }

                close(events[n].data.fd);

            }

        }

    }



    return 0;

}

参考资料:



你可能感兴趣的:(socket)