zoukankan      html  css  js  c++  java
  • 非阻塞connect:Web客户程序

     

    一、web.h

    #include    <stdio.h>
    #include    <netdb.h>
    #include    <errno.h>
    #include    <fcntl.h>
    #include    <stdlib.h>
    #include    <unistd.h>
    #include    <strings.h>
    #include    <sys/select.h>
    #include    <sys/socket.h>
    
    #define     MAXFILES    20
    #define     SERV        "80"      /* port number or service name */
    #define     MAXLINE     4096
    
    struct file {
      char    *f_name;                /* filename */
      char    *f_host;                /* hostname or IPv4/IPv6 address */
      int     f_fd;                   /* descriptor */
      int     f_flags;                /* F_xxx below */
    } file[MAXFILES];
    
    #define        F_CONNECTING    1    /* connect() in progress */
    #define        F_READING       2    /* connect() complete; now reading */
    #define        F_DONE          4    /* all done */
    
    #define        GET_CMD        "GET %s HTTP/1.0
    
    "
    
    /* globals */
    int     nconn, nfiles;
    int     nlefttoconn, nlefttoread;
    int     maxfd;
    fd_set  rset, wset;
    
    /* function prototypes */
    int     min(const int, const int);
    int     tcp_connect(const char *, const char *);
    void    err_ret(const char *, ...);
    void    err_sys(const char *, ...);
    void    err_quit(const char *, ...);
    void    home_page(const char *, const char *);
    void    start_connect(struct file *);
    void    write_get_cmd(struct file *);
    ssize_t writen(int, const void *, size_t);
    struct  addrinfo * host_serv(const char *, const char *, int, int);

    二、web.c

    #include    "web.h"
    
    int main(int argc, char **argv)
    {
        int          i, fd, maxnconn;
        int       flags, error;
        char      buf[MAXLINE];
        fd_set      rs, ws;
        socklen_t n;
    
        if (argc < 5) {
            err_quit("usage: web <conns> <hostname> <homepage> <file1> ...");
        }
        maxnconn = atoi(argv[1]);
    
        nfiles = min(argc - 4, MAXFILES);
        for (i = 0; i < nfiles; i++) {
            file[i].f_name = argv[i + 4];
            file[i].f_host = argv[2];
            file[i].f_flags = 0;
        }
        printf("nfiles = %d
    ", nfiles);
    
        home_page(argv[2], argv[3]);
    
        FD_ZERO(&rset);
        FD_ZERO(&wset);
        maxfd = -1;
        nlefttoread = nfiles;
        nlefttoconn = nfiles;
        nconn = 0;
    
        while (nlefttoread > 0) {
            while (nconn < maxnconn && nlefttoconn > 0) {
                /* find a file to read */
                for (i = 0 ; i < nfiles; i++) {
                    if (file[i].f_flags == 0) {
                        break;
                    }
                }
                if (i == nfiles) {
                    err_quit("nlefttoconn = %d but nothing found", nlefttoconn);
                }
                start_connect(&file[i]);
                nconn++;
                nlefttoconn--;
            }
    
            rs = rset;
            ws = wset;
            n = select(maxfd+1, &rs, &ws, NULL, NULL);
    
            for (i = 0; i < nfiles; i++) {
                flags = file[i].f_flags;
                if (flags == 0 || flags & F_DONE) {
                    continue;
                }
                fd = file[i].f_fd;
                if (flags & F_CONNECTING &&
                    (FD_ISSET(fd, &rs) || FD_ISSET(fd, &ws))) {
                    n = sizeof(error);
                    if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &n) < 0 ||
                        error != 0) {
                        err_ret("nonblocking connect failed for %s",
                                file[i].f_name);
                    }
                    /* connection established */
                    printf("connection established for %s
    ", file[i].f_name);
                    FD_CLR(fd, &wset);            /* no more writeability test */
                    write_get_cmd(&file[i]);      /* write() the GET command */
    
                } else if (flags & F_READING && FD_ISSET(fd, &rs)) {
                    if ( (n = read(fd, buf, sizeof(buf))) == 0) {
                        printf("end-of-file on %s
    ", file[i].f_name);
                        close(fd);
                        file[i].f_flags = F_DONE; /* clears F_READING */
                        FD_CLR(fd, &rset);
                        nconn--;
                        nlefttoread--;
                    } else {
                        printf("read %d bytes from %s
    ", n, file[i].f_name);
                    }
                }
            }
        }
        exit(0);
    }

    三、home_page.c

    #include    "web.h"
    
    void home_page(const char *host, const char *fname)
    {
        int        fd, n;
        char    line[MAXLINE];
    
        fd = tcp_connect(host, SERV); /* blocking connect() */
    
        n = snprintf(line, sizeof(line), GET_CMD, fname);
        if (writen(fd, line, n) == -1) {
            err_sys("write error");        
        }
    
        for ( ; ; ) {
            if ( (n = read(fd, line, MAXLINE)) == 0) {
                break;                /* server closed connection */
            }
            printf("read %d bytes of home page
    ", n);
            /* do whatever with data */
        }
        printf("end-of-file on home page
    ");
        close(fd);
    }

    四、start_connect.c

    #include    "web.h"
    
    void start_connect(struct file *fptr)
    {
        int       fd, flags, n;
        struct addrinfo    *ai;
    
        ai = host_serv(fptr->f_host, SERV, 0, SOCK_STREAM);
    
        fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
        fptr->f_fd = fd;
        printf("start_connect for %s, fd %d
    ", fptr->f_name, fd);
    
        /* Set socket nonblocking */
        flags = fcntl(fd, F_GETFL, 0);
        fcntl(fd, F_SETFL, flags | O_NONBLOCK);
    
        /* Initiate nonblocking connect to the server. */
        if ( (n = connect(fd, ai->ai_addr, ai->ai_addrlen)) < 0) {
            if (errno != EINPROGRESS) {
                err_sys("nonblocking connect error");
            }
            fptr->f_flags = F_CONNECTING;
            FD_SET(fd, &rset);      /* select for reading and writing */
            FD_SET(fd, &wset);
            if (fd > maxfd) {
                maxfd = fd;
            }
        } else if (n >= 0) {        /* connect is already done */
            write_get_cmd(fptr);    /* write() the GET command */
        }
    }

    五、tcp_connect.c

    #include    "web.h"
    
    int tcp_connect(const char *host, const char *serv)
    {
        int       sockfd, n;
        struct addrinfo    hints;
        struct addrinfo *res, *ressave;
    
        bzero(&hints, sizeof(struct addrinfo));
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;
    
        if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) {
            err_quit("tcp_connect error for %s, %s: %s",
                     host, serv, gai_strerror(n));
        }
        ressave = res;
    
        do {
            sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
            if (sockfd < 0) {
                continue;     /* ignore this one */
            }
            if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) {
                break;        /* success */
            }
            close(sockfd);    /* ignore this one */
        } while ( (res = res->ai_next) != NULL);
    
        if (res == NULL) {    /* errno set from final connect() */
            err_sys("tcp_connect error for %s, %s", host, serv);
        }
    
        freeaddrinfo(ressave);
    
        return (sockfd);
    }

    六、host_serv.c

    #include    <stddef.h>
    #include    <netdb.h>
    #include    <strings.h>
    
    struct addrinfo *host_serv(const char *host, 
        const char *serv, int family, int socktype)
    {
        int                n;
        struct addrinfo    hints, *res;
    
        bzero(&hints, sizeof(struct addrinfo));
        hints.ai_flags  = AI_CANONNAME;  /* always return canonical name */
        hints.ai_family = family;        /* AF_UNSPEC, AF_INET, AF_INET6, etc. */
        hints.ai_socktype = socktype;    /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */
    
        if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0) {
            return(NULL);
        }
    
        return (res); /* return pointer to first on linked list */
    }

    七、write_get_cmd.c

    #include    "web.h"
    
    void write_get_cmd(struct file *fptr)
    {
        int        n;
        char    line[MAXLINE];
    
        n = snprintf(line, sizeof(line), GET_CMD, fptr->f_name);
        writen(fptr->f_fd, line, n);
        printf("wrote %d bytes for %s
    ", n, fptr->f_name);
    
        fptr->f_flags = F_READING;            /* clears F_CONNECTING */
    
        FD_SET(fptr->f_fd, &rset);            /* will read server's reply */
        if (fptr->f_fd > maxfd) {
            maxfd = fptr->f_fd;
        }
    }

    八、writen.c

    #include <unistd.h>
    #include <errno.h>
    
    ssize_t writen(int fd, const void *vptr, size_t n) {
        size_t nleft;
        ssize_t nwriten;
        const char *ptr;
    
        ptr = vptr;
        nleft = n;
        while (nleft > 0) {
            if ( (nwriten = write(fd, ptr, nleft)) <= 0) {
                if (nwriten < 0 && errno == EINTR) {
                    nwriten = 0; /* call write() again */
                } else {
                    return (-1);
                }
            } 
            nleft -= nwriten;
            ptr += nwriten;
        }
        return (n - nwriten);
    }

    九、others.c

    int min(int num1, int num2) {
        return (num1<num2?num1:num2);
    }

    十、error.c

    #include    <stdio.h>
    #include    <errno.h>
    #include    <stdlib.h>
    #include    <string.h>
    #include    <stdarg.h>        /* ANSI C header file */
    #include    <syslog.h>        /* for syslog() */
    
    #define     MAXLINE     4096
    
    int        daemon_proc;       /* set nonzero by daemon_init() */
    
    static void    err_doit(int, int, const char *, va_list);
    
    /* Nonfatal error related to system call
     * Print message and return */
    
    void err_ret(const char *fmt, ...) {
    
        va_list        ap;    
    
        va_start(ap, fmt);    
        err_doit(1, LOG_INFO, fmt, ap);
        va_end(ap);
        return;
    }
    
    /* Fatal error related to system call
     * Print message and terminate */
    
    void err_sys(const char *fmt, ...) {
    
        va_list        ap;
    
        va_start(ap, fmt);
        err_doit(1, LOG_ERR, fmt, ap);
        va_end(ap);
        exit(1);
    }
    
    /* Fatal error related to system call
     * Print message, dump core, and terminate */
    
    void err_dump(const char *fmt, ...) {
        va_list        ap;
    
        va_start(ap, fmt);
        err_doit(1, LOG_ERR, fmt, ap);
        va_end(ap);
        abort();        /* dump core and terminate */
        exit(1);        /* shouldn't get here */
    }
    
    /* Nonfatal error unrelated to system call
     * Print message and return */
    
    void err_msg(const char *fmt, ...) {
    
        va_list        ap;
    
        va_start(ap, fmt);
        err_doit(0, LOG_INFO, fmt, ap);
        va_end(ap);
        return;
    }
    
    /* Fatal error unrelated to system call
     * Print message and terminate */
    
    void err_quit(const char *fmt, ...) {
    
        va_list        ap;
    
        va_start(ap, fmt);
        err_doit(0, LOG_ERR, fmt, ap);
        va_end(ap);
        exit(1);
    }
    
    /* Print message and return to caller
     * Caller specifies "errnoflag" and "level" */
    
    static void err_doit(int errnoflag, int level, const char *fmt, va_list ap) {
    
        int        errno_save, n;
        char    buf[MAXLINE + 1];
    
        errno_save = errno;                /* value caller might want printed */
    #ifdef    HAVE_VSNPRINTF
        vsnprintf(buf, MAXLINE, fmt, ap);  /* safe */
    #else
        vsprintf(buf, fmt, ap);            /* not safe */
    #endif
        n = strlen(buf);
        if (errnoflag)
            snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
        strcat(buf, "
    ");
    
        if (daemon_proc) {
            syslog(level, buf, NULL);
        } else {
            fflush(stdout);        /* in case stdout and stderr are the same */
            fputs(buf, stderr);
            fflush(stderr);
        }
        return;
    }

    十一、Makefile

    cccc = gcc
    prom = web
    deps = web.h
    objs = web.o home_page.o tcp_connect.o start_connect.o write_get_cmd.o writen.o others.o error.o host_serv.o
    
    $(prom): $(objs)
        $(cccc) -o $(prom) $(objs)
    
    %.o: %.c $(deps) 
        $(cccc) -c $< -o $@    
    
    clean: 
        rm -rf $(objs) $(prom)
  • 相关阅读:
    timer使用方法
    基于开源库jsoncpp的json字符串解析
    jsoncpp构造json字符串和json数组
    通过wifi连接android设备的方法
    Linux 利用管道父子进程间传递数据
    Mac OS X 下部分Android手机无法连接adb问题之解决方案
    android studio 慢的问题
    forever让nodejs后台运行
    js里面如何才能让成员方法去调用类中其他成员
    让Windows Server 2008 + IIS 7+ ASP.NET 支持10万并发请求
  • 原文地址:https://www.cnblogs.com/soldierback/p/10778743.html
Copyright © 2011-2022 走看看