zoukankan      html  css  js  c++  java
  • CSAPP-Tiny Web服务器【2】源码解析

    上篇博客:CSAPP-Tiny Web服务器【1】编译搭建 阐述Tiny编译搭建过程,接下来将对其源码进行深入解析~

    将一个实际的浏览器指向我们自己的服务器,看着它显示一个复杂的带有文本和图片的Web页面,真是颇具成就感~

    下面就来看看它的实现全过程:

    1. Tiny-main程序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    int main(int argc, char **argv)
    {
        int listenfd, connfd, port, clientlen;
        struct sockaddr_in clientaddr;
       
        /* Check command line args */
        if (argc != 2)
        {
            fprintf(stderr, "usage: %s <port> ", argv[0]);
            exit(1);
        }
        port = atoi(argv[1]);
       
        listenfd = Open_listenfd(port);
        while (1)
        {
            clientlen = sizeof(clientaddr);
            connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen); //line:netp:tiny:accept
            doit(connfd);                                             //line:netp:tiny:doit
            Close(connfd);                                            //line:netp:tiny:close
        }
    }

    Tiny是一个迭代服务器,监听在命令行中确定的端口上的连接请求。在通过open_listenedfd函数打开一个监听套接字以后,Tiny执行典型的无限服务循环,反复地接受一个连接(accept)请求,执行事务(doit),最后关闭连接描述符(close)。

    2. Tiny-doit函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    /*
     * doit - handle one HTTP request/response transaction
     */
    /* $begin doit */
    void doit(int fd)
    {
        int is_static;
        struct stat sbuf;
        char buf[MAXLINE], method[MAXLINE], uri[MAXLINE], version[MAXLINE];
        char filename[MAXLINE], cgiargs[MAXLINE];
        rio_t rio;
       
        /* Read request line and headers */
        Rio_readinitb(&rio, fd);    //Associate a descriptor with a read buffer and reset buffer
        Rio_readlineb(&rio, buf, MAXLINE);                   //line:netp:doit:readrequest
        sscanf(buf, "%s %s %s", method, uri, version);       //line:netp:doit:parserequest
        if (strcasecmp(method, "GET"))  //ignore case        //line:netp:doit:beginrequesterr
        {
            clienterror(fd, method, "501""Not Implemented",
                        "Tiny does not implement this method");
            return;
        }                                                    //line:netp:doit:endrequesterr
        read_requesthdrs(&rio);                              //line:netp:doit:readrequesthdrs
       
        /* Parse URI from GET request */
        is_static = parse_uri(uri, filename, cgiargs);       //line:netp:doit:staticcheck
        if (stat(filename, &sbuf) < 0)                       //line:netp:doit:beginnotfound
        {
            clienterror(fd, filename, "404""Not found",
                        "Tiny couldn't find this file");
            return;
        }                                                    //line:netp:doit:endnotfound
       
        if (is_static)   /* Serve static content */
        {
            if (!(S_ISREG(sbuf.st_mode)) || !(S_IRUSR & sbuf.st_mode))   //line:netp:doit:readable
            {
                clienterror(fd, filename, "403""Forbidden",
                            "Tiny couldn't read the file");
                return;
            }
            serve_static(fd, filename, sbuf.st_size);        //line:netp:doit:servestatic
        }
        else   /* Serve dynamic content */
        {
            if (!(S_ISREG(sbuf.st_mode)) || !(S_IXUSR & sbuf.st_mode))   //line:netp:doit:executable
            {
                clienterror(fd, filename, "403""Forbidden",
                            "Tiny couldn't run the CGI program");
                return;
            }
            serve_dynamic(fd, filename, cgiargs);            //line:netp:doit:servedynamic
        }
    }
    /* $end doit */

    解析:

    rio_readinitb(&rio,fd) :将程序的内部缓存区与描述符相关联。

    rio_readlineb(&rio,buf,MAXLINE) :从内部缓存区读出一个文本行至buf中,以null字符来结束这个文本行。当然,每行最大的字符数量不能超过MAXLINE。

    sscanf(buf,"%s %s %s",method,uri,version) :作为例子,一般此时buf中存放的是“GET / HTTP/1.1”,所以可知method为“GET”,uri为“/”,version为“HTTP/1.1”。其中sscanf的功能:把buf中的字符串以空格为分隔符分别传送到method、uri及version中。

    strcasecmp(method,"GET") :忽略大小写比较method与“GET”的大小,相等的话返回0。

    read_requesthdrs(&rio) :读并忽略请求报头。

    parse_uri(uri,filename,cgiargs) :解析uri,得文件名存入filename中,参数存入cgiargs中。

    stat(filename,&sbuf) :将文件filename中的各个元数据填写进sbuf中,如果找不到文件返回0。

    S_ISREG(sbuf,st_mode) :此文件为普通文件。

    S_IRUSR & sbuf.st_mode :有读取权限。

    serve_static(fd,filename,sbuf.st_size) :提供静态服务。

    serve_dynamic(fd,filename,cgiargs) :提供动态服务。

    (1)从doit函数中可知,我们的Tiny Web服务器只支持“GET”方法,其他方法请求的话则会发送一条错误消息,主程序返回,并等待下一个请求。否则,我们读并忽略请求报头。(其实,我们在请求服务时,直接不用写请求报头即可,写上只是为了符合HTTP协议标准)。

    (2)然后,我们将uri解析为一个文件名和一个可能为空的CGI参数,并且设置一个标志位,表明请求的是静态内容还是动态内容。通过stat函数判断文件是否存在。

    (3)最后,如果请求的是静态内容,我们需要检验它是否是一个普通文件,并且可读。条件通过,则我们服务器向客服端发送静态内容;相似的,如果请求的是动态内容,我就核实该文件是否是可执行文件,如果是则执行该文件,并提供动态功能。

    3. Tiny的clienterror函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    /*
     * clienterror - returns an error message to the client
     */
    /* $begin clienterror */
    void clienterror(int fd, char *cause, char *errnum,
                     char *shortmsg, char *longmsg)
    {
        char buf[MAXLINE], body[MAXBUF];
       
        /* Build the HTTP response body */
        sprintf(body, "<html><title>Tiny Error</title>");
        sprintf(body, "%s<body bgcolor=""ffffff""> ", body);
        sprintf(body, "%s%s: %s ", body, errnum, shortmsg);
        sprintf(body, "%s<p>%s: %s ", body, longmsg, cause);
        sprintf(body, "%s<hr><em>The Tiny Web server</em> ", body);
       
        /* Print the HTTP response */
        sprintf(buf, "HTTP/1.0 %s %s ", errnum, shortmsg);
        Rio_writen(fd, buf, strlen(buf));
        sprintf(buf, "Content-type: text/html ");
        Rio_writen(fd, buf, strlen(buf));
        sprintf(buf, "Content-length: %d ", (int)strlen(body));
        Rio_writen(fd, buf, strlen(buf));
        Rio_writen(fd, body, strlen(body));
    }
    /* $end clienterror */

    向客户端返回错误信息。

    sprintf(buf,"------------"):将字符串“------------”输送到buf中。

    rio_writen(fd,buf,strlen(buf)):将buf中的字符串写入fd描述符中。

    4. Tiny的read_requesthdrs函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /*
     * read_requesthdrs - read and parse HTTP request headers
     */
    /* $begin read_requesthdrs */
    void read_requesthdrs(rio_t *rp)
    {
        char buf[MAXLINE];
       
        Rio_readlineb(rp, buf, MAXLINE);
        while(strcmp(buf, " "))            //line:netp:readhdrs:checkterm
        {
            Rio_readlineb(rp, buf, MAXLINE);
            printf("%s", buf);
        }
        return;
    }
    /* $end read_requesthdrs */

    Tiny不需要请求报头中的任何信息,所以我们这个函数就是来跳过这些请求报头的。具体做法就是读这些请求报头,直到空行,然后返回。OK!

    5. Tiny的parse_uri函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    /*
     * parse_uri - parse URI into filename and CGI args
     *             return 0 if dynamic content, 1 if static
     */
    /* $begin parse_uri */
    int parse_uri(char *uri, char *filename, char *cgiargs)
    {
        char *ptr;
       
        if (!strstr(uri, "cgi-bin")) {  /* Static content */ //line:netp:parseuri:isstatic
            strcpy(cgiargs, "");                             //line:netp:parseuri:clearcgi
            strcpy(filename, ".");                           //line:netp:parseuri:beginconvert1
            strcat(filename, uri);                           //line:netp:parseuri:endconvert1
            if (uri[strlen(uri)-1] == '/')                   //line:netp:parseuri:slashcheck
                strcat(filename, "home.html");               //line:netp:parseuri:appenddefault
            return 1;
        }
        else {  /* Dynamic content */                        //line:netp:parseuri:isdynamic
            ptr = index(uri, '?');                           //line:netp:parseuri:beginextract
            if (ptr)
            {
                strcpy(cgiargs, ptr+1);
                *ptr = '';
            }
            else
                strcpy(cgiargs, "");                         //line:netp:parseuri:endextract
            strcpy(filename, ".");                           //line:netp:parseuri:beginconvert2
            strcat(filename, uri);                           //line:netp:parseuri:endconvert2
            return 0;
        }
    }
    /* $end parse_uri */

    根据uri中是否含有cgi-bin来判断请求的是静态内容还是动态内容。如果没有cgi-bin,则说明请求的是静态内容。那么,我们需把cgiargs置NULL,然后获得文件名,如果我们请求的uri最后为 “/”,则自动添加上home.html。比如说,我们请求的是“/”,则返回的文件名为“./home.html”,而我们请求“/logo.gif”,则返回的文件名为“./logo.gif”。如果uri中含有cgi-bin,则说明请求的是动态内容。那么,我们需要把参数拷贝到cgiargs中,把要执行的文件路径写入filename。举例来说,uri为/cgi-bin/adder?3&5,则cigargs中存放的是3&5,filename中存放的是“./cgi-bin/adder”,OK!

    index(uri,'?') : 找出uri字符串中第一个出现参数‘?’的地址,并将此地址返回。

    6. Tiny的serve_static函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    /*
     * serve_static - copy a file back to the client
     */
    /* $begin serve_static */
    void serve_static(int fd, char *filename, int filesize)
    {
        int srcfd;
        char *srcp, filetype[MAXLINE], buf[MAXBUF];
       
        /* Send response headers to client */
        get_filetype(filename, filetype);       //line:netp:servestatic:getfiletype
        sprintf(buf, "HTTP/1.0 200 OK ");    //line:netp:servestatic:beginserve
        sprintf(buf, "%sServer: Tiny Web Server ", buf);
        sprintf(buf, "%sContent-length: %d ", buf, filesize);
        sprintf(buf, "%sContent-type: %s ", buf, filetype);
        Rio_writen(fd, buf, strlen(buf));       //line:netp:servestatic:endserve
       
        /* Send response body to client */
        srcfd = Open(filename, O_RDONLY, 0);    //line:netp:servestatic:open
        srcp = Mmap(0, filesize, PROT_READ, MAP_PRIVATE, srcfd, 0);//line:netp:servestatic:mmap
        Close(srcfd);                           //line:netp:servestatic:close
        Rio_writen(fd, srcp, filesize);         //line:netp:servestatic:write
        Munmap(srcp, filesize);                 //line:netp:servestatic:munmap
    }
       
    /*
     * get_filetype - derive file type from file name
     */
    void get_filetype(char *filename, char *filetype)
    {
        if (strstr(filename, ".html"))
            strcpy(filetype, "text/html");
        else if (strstr(filename, ".gif"))
            strcpy(filetype, "image/gif");
        else if (strstr(filename, ".jpg"))
            strcpy(filetype, "image/jpeg");
        else
            strcpy(filetype, "text/plain");
    }
    /* $end serve_static */

    打开文件名为filename的文件,把它映射到一个虚拟存储器空间,将文件的前filesize字节映射到从地址srcp开始的虚拟存储区域。关闭文件描述符srcfd,把虚拟存储区的数据写入fd描述符,最后释放虚拟存储器区域。

    7. Tiny的serve_dynamic函数

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /*
     * serve_dynamic - run a CGI program on behalf of the client
     */
    /* $begin serve_dynamic */
    void serve_dynamic(int fd, char *filename, char *cgiargs)
    {
        char buf[MAXLINE], *emptylist[] = { NULL };
       
        /* Return first part of HTTP response */
        sprintf(buf, "HTTP/1.0 200 OK ");
        Rio_writen(fd, buf, strlen(buf));
        sprintf(buf, "Server: Tiny Web Server ");
        Rio_writen(fd, buf, strlen(buf));
       
        if (Fork() == 0) { /* child */ //line:netp:servedynamic:fork
            /* Real server would set all CGI vars here */
            setenv("QUERY_STRING", cgiargs, 1); //line:netp:servedynamic:setenv
            Dup2(fd, STDOUT_FILENO);         /* Redirect stdout to client */ //line:netp:servedynamic:dup2
            Execve(filename, emptylist, environ); /* Run CGI program */ //line:netp:servedynamic:execve
        }
        Wait(NULL); /* Parent waits for and reaps child */ //line:netp:servedynamic:wait
    }
    /* $end serve_dynamic */

    Tiny在发送了响应的第一部分后,通过派生一个子进程并在子进程的上下文中运行一个cgi程序(可执行文件),来提供各种类型的动态内容。

    setenv("QUERY_STRING",cgiargs,1) :设置QUERY_STRING环境变量。

    dup2 (fd,STDOUT_FILENO) :重定向它的标准输出到已连接描述符。此时,任何写到标准输出的东西都直接写到客户端。

    execve(filename,emptylist,environ) :加载运行cgi程序。

     

    8. Tiny的准备-CSAPP 封装 csapp.h csapp.c

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    /* $begin csapp.h */
    #ifndef __CSAPP_H__
    #define __CSAPP_H__
       
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <ctype.h>
    #include <setjmp.h>
    #include <signal.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <sys/wait.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <sys/mman.h>
    #include <errno.h>
    #include <math.h>
    #include <pthread.h>
    #include <semaphore.h>
    #include <sys/socket.h>
    #include <netdb.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
       
    /* Default file permissions are DEF_MODE & ~DEF_UMASK */
    /* $begin createmasks */
    #define DEF_MODE   S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH
    #define DEF_UMASK  S_IWGRP|S_IWOTH
    /* $end createmasks */
       
    /* Simplifies calls to bind(), connect(), and accept() */
    /* $begin sockaddrdef */
    typedef struct sockaddr SA;
    /* $end sockaddrdef */
       
    /* Persistent state for the robust I/O (Rio) package */
    /* $begin rio_t */
    #define RIO_BUFSIZE 8192
    typedef struct
    {
        int rio_fd;                /* descriptor for this internal buf */
        int rio_cnt;               /* unread bytes in internal buf */
        char *rio_bufptr;          /* next unread byte in internal buf */
        char rio_buf[RIO_BUFSIZE]; /* internal buffer */
    } rio_t;
    /* $end rio_t */
       
    /* External variables */
    extern int h_errno;    /* defined by BIND for DNS errors */
    extern char **environ; /* defined by libc */
       
    /* Misc constants */
    #define MAXLINE  8192  /* max text line length */
    #define MAXBUF   8192  /* max I/O buffer size */
    #define LISTENQ  1024  /* second argument to listen() */
       
    /* Our own error-handling functions */
    void unix_error(char *msg);
    void posix_error(int code, char *msg);
    void dns_error(char *msg);
    void app_error(char *msg);
       
    /* Process control wrappers */
    pid_t Fork(void);
    void Execve(const char *filename, char *const argv[], char *const envp[]);
    pid_t Wait(int *status);
    pid_t Waitpid(pid_t pid, int *iptr, int options);
    void Kill(pid_t pid, int signum);
    unsigned int Sleep(unsigned int secs);
    void Pause(void);
    unsigned int Alarm(unsigned int seconds);
    void Setpgid(pid_t pid, pid_t pgid);
    pid_t Getpgrp();
       
    /* Signal wrappers */
    typedef void handler_t(int);
    handler_t *Signal(int signum, handler_t *handler);
    void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
    void Sigemptyset(sigset_t *set);
    void Sigfillset(sigset_t *set);
    void Sigaddset(sigset_t *set, int signum);
    void Sigdelset(sigset_t *set, int signum);
    int Sigismember(const sigset_t *set, int signum);
       
    /* Unix I/O wrappers */
    int Open(const char *pathname, int flags, mode_t mode);
    ssize_t Read(int fd, void *buf, size_t count);
    ssize_t Write(int fd, const void *buf, size_t count);
    off_t Lseek(int fildes, off_t offset, int whence);
    void Close(int fd);
    int Select(int  n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
               struct timeval *timeout);
    int Dup2(int fd1, int fd2);
    void Stat(const char *filename, struct stat *buf);
    void Fstat(int fd, struct stat *buf) ;
       
    /* Memory mapping wrappers */
    void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);
    void Munmap(void *start, size_t length);
       
    /* Standard I/O wrappers */
    void Fclose(FILE *fp);
    FILE *Fdopen(int fd, const char *type);
    char *Fgets(char *ptr, int n, FILE *stream);
    FILE *Fopen(const char *filename, const char *mode);
    void Fputs(const char *ptr, FILE *stream);
    size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
       
    /* Dynamic storage allocation wrappers */
    void *Malloc(size_t size);
    void *Realloc(void *ptr, size_t size);
    void *Calloc(size_t nmemb, size_t size);
    void Free(void *ptr);
       
    /* Sockets interface wrappers */
    int Socket(int domain, int type, int protocol);
    void Setsockopt(int s, int level, int optname, const void *optval, int optlen);
    void Bind(int sockfd, struct sockaddr *my_addr, int addrlen);
    void Listen(int s, int backlog);
    int Accept(int s, struct sockaddr *addr, socklen_t *addrlen);
    void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen);
       
    /* DNS wrappers */
    struct hostent *Gethostbyname(const char *name);
    struct hostent *Gethostbyaddr(const char *addr, int len, int type);
       
    /* Pthreads thread control wrappers */
    void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
                        void * (*routine)(void *), void *argp);
    void Pthread_join(pthread_t tid, void **thread_return);
    void Pthread_cancel(pthread_t tid);
    void Pthread_detach(pthread_t tid);
    void Pthread_exit(void *retval);
    pthread_t Pthread_self(void);
    void Pthread_once(pthread_once_t *once_control, void (*init_function)());
       
    /* POSIX semaphore wrappers */
    void Sem_init(sem_t *sem, int pshared, unsigned int value);
    void P(sem_t *sem);
    void V(sem_t *sem);
       
    /* Rio (Robust I/O) package */
    ssize_t rio_readn(int fd, void *usrbuf, size_t n);
    ssize_t rio_writen(int fd, void *usrbuf, size_t n);
    void rio_readinitb(rio_t *rp, int fd);
    ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n);
    ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
       
    /* Wrappers for Rio package */
    ssize_t Rio_readn(int fd, void *usrbuf, size_t n);
    void Rio_writen(int fd, void *usrbuf, size_t n);
    void Rio_readinitb(rio_t *rp, int fd);
    ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n);
    ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen);
       
    /* Client/server helper functions */
    int open_clientfd(char *hostname, int portno);
    int open_listenfd(int portno);
       
    /* Wrappers for client/server helper functions */
    int Open_clientfd(char *hostname, int port);
    int Open_listenfd(int port);
       
    #endif /* __CSAPP_H__ */
    /* $end csapp.h */

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
    588
    589
    590
    591
    592
    593
    594
    595
    596
    597
    598
    599
    600
    601
    602
    603
    604
    605
    606
    607
    608
    609
    610
    611
    612
    613
    614
    615
    616
    617
    618
    619
    620
    621
    622
    623
    624
    625
    626
    627
    628
    629
    630
    631
    632
    633
    634
    635
    636
    637
    638
    639
    640
    641
    642
    643
    644
    645
    646
    647
    648
    649
    650
    651
    652
    653
    654
    655
    656
    657
    658
    659
    660
    661
    662
    663
    664
    665
    666
    667
    668
    669
    670
    671
    672
    673
    674
    675
    676
    677
    678
    679
    680
    681
    682
    683
    684
    685
    686
    687
    688
    689
    690
    691
    692
    693
    694
    695
    696
    697
    698
    699
    700
    701
    702
    703
    704
    705
    706
    707
    708
    709
    710
    711
    712
    713
    714
    715
    716
    717
    718
    719
    720
    721
    722
    723
    724
    725
    726
    727
    728
    729
    730
    731
    732
    733
    734
    735
    736
    737
    738
    739
    740
    741
    742
    743
    744
    745
    746
    747
    748
    749
    750
    751
    752
    753
    754
    755
    756
    757
    758
    759
    760
    761
    762
    763
    764
    765
    766
    767
    768
    769
    770
    771
    772
    773
    774
    775
    776
    777
    778
    779
    780
    781
    782
    783
    784
    785
    786
    787
    788
    789
    790
    791
    792
    793
    794
    795
    796
    797
    798
    799
    800
    801
    802
    803
    804
    805
    806
    807
    808
    809
    810
    811
    812
    813
    814
    815
    816
    817
    818
    819
    820
    821
    822
    823
    824
    825
    826
    827
    828
    829
    830
    831
    832
    833
    834
    835
    836
    /* $begin csapp.c */
    #include "csapp.h"
       
    /**************************
     * Error-handling functions
     **************************/
    /* $begin errorfuns */
    /* $begin unixerror */
    void unix_error(char *msg) /* unix-style error */
    {
        fprintf(stderr, "%s: %s ", msg, strerror(errno));
        exit(0);
    }
    /* $end unixerror */
       
    void posix_error(int code, char *msg) /* posix-style error */
    {
        fprintf(stderr, "%s: %s ", msg, strerror(code));
        exit(0);
    }
       
    void dns_error(char *msg) /* dns-style error */
    {
        fprintf(stderr, "%s: DNS error %d ", msg, h_errno);
        exit(0);
    }
       
    void app_error(char *msg) /* application error */
    {
        fprintf(stderr, "%s ", msg);
        exit(0);
    }
    /* $end errorfuns */
       
    /*********************************************
     * Wrappers for Unix process control functions
     ********************************************/
       
    /* $begin forkwrapper */
    pid_t Fork(void)
    {
        pid_t pid;
       
        if ((pid = fork()) < 0)
            unix_error("Fork error");
        return pid;
    }
    /* $end forkwrapper */
       
    void Execve(const char *filename, char *const argv[], char *const envp[])
    {
        if (execve(filename, argv, envp) < 0)
            unix_error("Execve error");
    }
       
    /* $begin wait */
    pid_t Wait(int *status)
    {
        pid_t pid;
       
        if ((pid  = wait(status)) < 0)
            unix_error("Wait error");
        return pid;
    }
    /* $end wait */
       
    pid_t Waitpid(pid_t pid, int *iptr, int options)
    {
        pid_t retpid;
       
        if ((retpid  = waitpid(pid, iptr, options)) < 0)
            unix_error("Waitpid error");
        return(retpid);
    }
       
    /* $begin kill */
    void Kill(pid_t pid, int signum)
    {
        int rc;
       
        if ((rc = kill(pid, signum)) < 0)
            unix_error("Kill error");
    }
    /* $end kill */
       
    void Pause()
    {
        (void)pause();
        return;
    }
       
    unsigned int Sleep(unsigned int secs)
    {
        unsigned int rc;
       
        if ((rc = sleep(secs)) < 0)
            unix_error("Sleep error");
        return rc;
    }
       
    unsigned int Alarm(unsigned int seconds)
    {
        return alarm(seconds);
    }
       
    void Setpgid(pid_t pid, pid_t pgid)
    {
        int rc;
       
        if ((rc = setpgid(pid, pgid)) < 0)
            unix_error("Setpgid error");
        return;
    }
       
    pid_t Getpgrp(void)
    {
        return getpgrp();
    }
       
    /************************************
     * Wrappers for Unix signal functions
     ***********************************/
       
    /* $begin sigaction */
    handler_t *Signal(int signum, handler_t *handler)
    {
        struct sigaction action, old_action;
       
        action.sa_handler = handler;
        sigemptyset(&action.sa_mask); /* block sigs of type being handled */
        action.sa_flags = SA_RESTART; /* restart syscalls if possible */
       
        if (sigaction(signum, &action, &old_action) < 0)
            unix_error("Signal error");
        return (old_action.sa_handler);
    }
    /* $end sigaction */
       
    void Sigprocmask(int how, const sigset_t *set, sigset_t *oldset)
    {
        if (sigprocmask(how, set, oldset) < 0)
            unix_error("Sigprocmask error");
        return;
    }
       
    void Sigemptyset(sigset_t *set)
    {
        if (sigemptyset(set) < 0)
            unix_error("Sigemptyset error");
        return;
    }
       
    void Sigfillset(sigset_t *set)
    {
        if (sigfillset(set) < 0)
            unix_error("Sigfillset error");
        return;
    }
       
    void Sigaddset(sigset_t *set, int signum)
    {
        if (sigaddset(set, signum) < 0)
            unix_error("Sigaddset error");
        return;
    }
       
    void Sigdelset(sigset_t *set, int signum)
    {
        if (sigdelset(set, signum) < 0)
            unix_error("Sigdelset error");
        return;
    }
       
    int Sigismember(const sigset_t *set, int signum)
    {
        int rc;
        if ((rc = sigismember(set, signum)) < 0)
            unix_error("Sigismember error");
        return rc;
    }
       
       
    /********************************
     * Wrappers for Unix I/O routines
     ********************************/
       
    int Open(const char *pathname, int flags, mode_t mode)
    {
        int rc;
       
        if ((rc = open(pathname, flags, mode))  < 0)
            unix_error("Open error");
        return rc;
    }
       
    ssize_t Read(int fd, void *buf, size_t count)
    {
        ssize_t rc;
       
        if ((rc = read(fd, buf, count)) < 0)
            unix_error("Read error");
        return rc;
    }
       
    ssize_t Write(int fd, const void *buf, size_t count)
    {
        ssize_t rc;
       
        if ((rc = write(fd, buf, count)) < 0)
            unix_error("Write error");
        return rc;
    }
       
    off_t Lseek(int fildes, off_t offset, int whence)
    {
        off_t rc;
       
        if ((rc = lseek(fildes, offset, whence)) < 0)
            unix_error("Lseek error");
        return rc;
    }
       
    void Close(int fd)
    {
        int rc;
       
        if ((rc = close(fd)) < 0)
            unix_error("Close error");
    }
       
    int Select(int  n, fd_set *readfds, fd_set *writefds,
               fd_set *exceptfds, struct timeval *timeout)
    {
        int rc;
       
        if ((rc = select(n, readfds, writefds, exceptfds, timeout)) < 0)
            unix_error("Select error");
        return rc;
    }
       
    int Dup2(int fd1, int fd2)
    {
        int rc;
       
        if ((rc = dup2(fd1, fd2)) < 0)
            unix_error("Dup2 error");
        return rc;
    }
       
    void Stat(const char *filename, struct stat *buf)
    {
        if (stat(filename, buf) < 0)
            unix_error("Stat error");
    }
       
    void Fstat(int fd, struct stat *buf)
    {
        if (fstat(fd, buf) < 0)
            unix_error("Fstat error");
    }
       
    /***************************************
     * Wrappers for memory mapping functions
     ***************************************/
    void *Mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
    {
        void *ptr;
       
        if ((ptr = mmap(addr, len, prot, flags, fd, offset)) == ((void *) -1))
            unix_error("mmap error");
        return(ptr);
    }
       
    void Munmap(void *start, size_t length)
    {
        if (munmap(start, length) < 0)
            unix_error("munmap error");
    }
       
    /***************************************************
     * Wrappers for dynamic storage allocation functions
     ***************************************************/
       
    void *Malloc(size_t size)
    {
        void *p;
       
        if ((p  = malloc(size)) == NULL)
            unix_error("Malloc error");
        return p;
    }
       
    void *Realloc(void *ptr, size_t size)
    {
        void *p;
       
        if ((p  = realloc(ptr, size)) == NULL)
            unix_error("Realloc error");
        return p;
    }
       
    void *Calloc(size_t nmemb, size_t size)
    {
        void *p;
       
        if ((p = calloc(nmemb, size)) == NULL)
            unix_error("Calloc error");
        return p;
    }
       
    void Free(void *ptr)
    {
        free(ptr);
    }
       
    /******************************************
     * Wrappers for the Standard I/O functions.
     ******************************************/
    void Fclose(FILE *fp)
    {
        if (fclose(fp) != 0)
            unix_error("Fclose error");
    }
       
    FILE *Fdopen(int fd, const char *type)
    {
        FILE *fp;
       
        if ((fp = fdopen(fd, type)) == NULL)
            unix_error("Fdopen error");
       
        return fp;
    }
       
    char *Fgets(char *ptr, int n, FILE *stream)
    {
        char *rptr;
       
        if (((rptr = fgets(ptr, n, stream)) == NULL) && ferror(stream))
            app_error("Fgets error");
       
        return rptr;
    }
       
    FILE *Fopen(const char *filename, const char *mode)
    {
        FILE *fp;
       
        if ((fp = fopen(filename, mode)) == NULL)
            unix_error("Fopen error");
       
        return fp;
    }
       
    void Fputs(const char *ptr, FILE *stream)
    {
        if (fputs(ptr, stream) == EOF)
            unix_error("Fputs error");
    }
       
    size_t Fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
    {
        size_t n;
       
        if (((n = fread(ptr, size, nmemb, stream)) < nmemb) && ferror(stream))
            unix_error("Fread error");
        return n;
    }
       
    void Fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
    {
        if (fwrite(ptr, size, nmemb, stream) < nmemb)
            unix_error("Fwrite error");
    }
       
       
    /****************************
     * Sockets interface wrappers
     ****************************/
       
    int Socket(int domain, int type, int protocol)
    {
        int rc;
       
        if ((rc = socket(domain, type, protocol)) < 0)
            unix_error("Socket error");
        return rc;
    }
       
    void Setsockopt(int s, int level, int optname, const void *optval, int optlen)
    {
        int rc;
       
        if ((rc = setsockopt(s, level, optname, optval, optlen)) < 0)
            unix_error("Setsockopt error");
    }
       
    void Bind(int sockfd, struct sockaddr *my_addr, int addrlen)
    {
        int rc;
       
        if ((rc = bind(sockfd, my_addr, addrlen)) < 0)
            unix_error("Bind error");
    }
       
    void Listen(int s, int backlog)
    {
        int rc;
       
        if ((rc = listen(s,  backlog)) < 0)
            unix_error("Listen error");
    }
       
    int Accept(int s, struct sockaddr *addr, socklen_t *addrlen)
    {
        int rc;
       
        if ((rc = accept(s, addr, addrlen)) < 0)
            unix_error("Accept error");
        return rc;
    }
       
    void Connect(int sockfd, struct sockaddr *serv_addr, int addrlen)
    {
        int rc;
       
        if ((rc = connect(sockfd, serv_addr, addrlen)) < 0)
            unix_error("Connect error");
    }
       
    /************************
     * DNS interface wrappers
     ***********************/
       
    /* $begin gethostbyname */
    struct hostent *Gethostbyname(const char *name)
    {
        struct hostent *p;
       
        if ((p = gethostbyname(name)) == NULL)
            dns_error("Gethostbyname error");
        return p;
    }
    /* $end gethostbyname */
       
    struct hostent *Gethostbyaddr(const char *addr, int len, int type)
    {
        struct hostent *p;
       
        if ((p = gethostbyaddr(addr, len, type)) == NULL)
            dns_error("Gethostbyaddr error");
        return p;
    }
       
    /************************************************
     * Wrappers for Pthreads thread control functions
     ************************************************/
       
    void Pthread_create(pthread_t *tidp, pthread_attr_t *attrp,
                        void * (*routine)(void *), void *argp)
    {
        int rc;
       
        if ((rc = pthread_create(tidp, attrp, routine, argp)) != 0)
            posix_error(rc, "Pthread_create error");
    }
       
    void Pthread_cancel(pthread_t tid)
    {
        int rc;
       
        if ((rc = pthread_cancel(tid)) != 0)
            posix_error(rc, "Pthread_cancel error");
    }
       
    void Pthread_join(pthread_t tid, void **thread_return)
    {
        int rc;
       
        if ((rc = pthread_join(tid, thread_return)) != 0)
            posix_error(rc, "Pthread_join error");
    }
       
    /* $begin detach */
    void Pthread_detach(pthread_t tid)
    {
        int rc;
       
        if ((rc = pthread_detach(tid)) != 0)
            posix_error(rc, "Pthread_detach error");
    }
    /* $end detach */
       
    void Pthread_exit(void *retval)
    {
        pthread_exit(retval);
    }
       
    pthread_t Pthread_self(void)
    {
        return pthread_self();
    }
       
    void Pthread_once(pthread_once_t *once_control, void (*init_function)())
    {
        pthread_once(once_control, init_function);
    }
       
    /*******************************
     * Wrappers for Posix semaphores
     *******************************/
       
    void Sem_init(sem_t *sem, int pshared, unsigned int value)
    {
        if (sem_init(sem, pshared, value) < 0)
            unix_error("Sem_init error");
    }
       
    void P(sem_t *sem)
    {
        if (sem_wait(sem) < 0)
            unix_error("P error");
    }
       
    void V(sem_t *sem)
    {
        if (sem_post(sem) < 0)
            unix_error("V error");
    }
       
    /*********************************************************************
     * The Rio package - robust I/O functions
     **********************************************************************/
    /*
     * rio_readn - robustly read n bytes (unbuffered)
     */
    /* $begin rio_readn */
    ssize_t rio_readn(int fd, void *usrbuf, size_t n)
    {
        size_t nleft = n;
        ssize_t nread;
        char *bufp = usrbuf;
       
        while (nleft > 0)
        {
            if ((nread = read(fd, bufp, nleft)) < 0)
            {
                if (errno == EINTR) /* interrupted by sig handler return */
                    nread = 0;      /* and call read() again */
                else
                    return -1;      /* errno set by read() */
            }
            else if (nread == 0)
                break;              /* EOF */
            nleft -= nread;
            bufp += nread;
        }
        return (n - nleft);         /* return >= 0 */
    }
    /* $end rio_readn */
       
    /*
     * rio_writen - robustly write n bytes (unbuffered)
     */
    /* $begin rio_writen */
    ssize_t rio_writen(int fd, void *usrbuf, size_t n)
    {
        size_t nleft = n;
        ssize_t nwritten;
        char *bufp = usrbuf;
       
        while (nleft > 0)
        {
            if ((nwritten = write(fd, bufp, nleft)) <= 0)
            {
                if (errno == EINTR)  /* interrupted by sig handler return */
                    nwritten = 0;    /* and call write() again */
                else
                    return -1;       /* errno set by write() */
            }
            nleft -= nwritten;
            bufp += nwritten;
        }
        return n;
    }
    /* $end rio_writen */
       
       
    /*
     * rio_read - This is a wrapper for the Unix read() function that
     *    transfers min(n, rio_cnt) bytes from an internal buffer to a user
     *    buffer, where n is the number of bytes requested by the user and
     *    rio_cnt is the number of unread bytes in the internal buffer. On
     *    entry, rio_read() refills the internal buffer via a call to
     *    read() if the internal buffer is empty.
     */
    /* $begin rio_read */
    static ssize_t rio_read(rio_t *rp, char *usrbuf, size_t n)
    {
        int cnt;
       
        while (rp->rio_cnt <= 0)    /* refill if buf is empty */
        {
            rp->rio_cnt = read(rp->rio_fd, rp->rio_buf,
                               sizeof(rp->rio_buf));
            if (rp->rio_cnt < 0)
            {
                if (errno != EINTR) /* interrupted by sig handler return */
                    return -1;
            }
            else if (rp->rio_cnt == 0)  /* EOF */
                return 0;
            else
                rp->rio_bufptr = rp->rio_buf; /* reset buffer ptr */
        }
       
        /* Copy min(n, rp->rio_cnt) bytes from internal buf to user buf */
        cnt = n;
        if (rp->rio_cnt < n)
            cnt = rp->rio_cnt;
        memcpy(usrbuf, rp->rio_bufptr, cnt);
        rp->rio_bufptr += cnt;
        rp->rio_cnt -= cnt;
        return cnt;
    }
    /* $end rio_read */
       
    /*
     * rio_readinitb - Associate a descriptor with a read buffer and reset buffer
     */
    /* $begin rio_readinitb */
    void rio_readinitb(rio_t *rp, int fd)
    {
        rp->rio_fd = fd;
        rp->rio_cnt = 0;
        rp->rio_bufptr = rp->rio_buf;
    }
    /* $end rio_readinitb */
       
    /*
     * rio_readnb - Robustly read n bytes (buffered)
     */
    /* $begin rio_readnb */
    ssize_t rio_readnb(rio_t *rp, void *usrbuf, size_t n)
    {
        size_t nleft = n;
        ssize_t nread;
        char *bufp = usrbuf;
       
        while (nleft > 0)
        {
            if ((nread = rio_read(rp, bufp, nleft)) < 0)
            {
                if (errno == EINTR) /* interrupted by sig handler return */
                    nread = 0;      /* call read() again */
                else
                    return -1;      /* errno set by read() */
            }
            else if (nread == 0)
                break;              /* EOF */
            nleft -= nread;
            bufp += nread;
        }
        return (n - nleft);         /* return >= 0 */
    }
    /* $end rio_readnb */
       
    /*
     * rio_readlineb - robustly read a text line (buffered)
     */
    /* $begin rio_readlineb */
    ssize_t rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
    {
        int n, rc;
        char c, *bufp = usrbuf;
       
        for (n = 1; n < maxlen; n++)
        {
            if ((rc = rio_read(rp, &c, 1)) == 1)
            {
                *bufp++ = c;
                if (c == ' ')
                    break;
            }
            else if (rc == 0)
            {
                if (n == 1)
                    return 0; /* EOF, no data read */
                else
                    break;    /* EOF, some data was read */
            }
            else
                return -1;    /* error */
        }
        *bufp = 0;
        return n;
    }
    /* $end rio_readlineb */
       
    /**********************************
     * Wrappers for robust I/O routines
     **********************************/
    ssize_t Rio_readn(int fd, void *ptr, size_t nbytes)
    {
        ssize_t n;
       
        if ((n = rio_readn(fd, ptr, nbytes)) < 0)
            unix_error("Rio_readn error");
        return n;
    }
       
    void Rio_writen(int fd, void *usrbuf, size_t n)
    {
        if (rio_writen(fd, usrbuf, n) != n)
            unix_error("Rio_writen error");
    }
       
    void Rio_readinitb(rio_t *rp, int fd)
    {
        rio_readinitb(rp, fd);
    }
       
    ssize_t Rio_readnb(rio_t *rp, void *usrbuf, size_t n)
    {
        ssize_t rc;
       
        if ((rc = rio_readnb(rp, usrbuf, n)) < 0)
            unix_error("Rio_readnb error");
        return rc;
    }
       
    ssize_t Rio_readlineb(rio_t *rp, void *usrbuf, size_t maxlen)
    {
        ssize_t rc;
       
        if ((rc = rio_readlineb(rp, usrbuf, maxlen)) < 0)
            unix_error("Rio_readlineb error");
        return rc;
    }
       
    /********************************
     * Client/server helper functions
     ********************************/
    /*
     * open_clientfd - open connection to server at <hostname, port>
     *   and return a socket descriptor ready for reading and writing.
     *   Returns -1 and sets errno on Unix error.
     *   Returns -2 and sets h_errno on DNS (gethostbyname) error.
     */
    /* $begin open_clientfd */
    int open_clientfd(char *hostname, int port)
    {
        int clientfd;
        struct hostent *hp;
        struct sockaddr_in serveraddr;
       
        if ((clientfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            return -1; /* check errno for cause of error */
       
        /* Fill in the server's IP address and port */
        if ((hp = gethostbyname(hostname)) == NULL)
            return -2; /* check h_errno for cause of error */
        bzero((char *) &serveraddr, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        bcopy((char *)hp->h_addr_list[0],
              (char *)&serveraddr.sin_addr.s_addr, hp->h_length);
        serveraddr.sin_port = htons(port);
       
        /* Establish a connection with the server */
        if (connect(clientfd, (SA *) &serveraddr, sizeof(serveraddr)) < 0)
            return -1;
        return clientfd;
    }
    /* $end open_clientfd */
       
    /*
     * open_listenfd - open and return a listening socket on port
     *     Returns -1 and sets errno on Unix error.
     */
    /* $begin open_listenfd */
    int open_listenfd(int port)
    {
        int listenfd, optval=1;
        struct sockaddr_in serveraddr;
       
        /* Create a socket descriptor */
        if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
            return -1;
       
        /* Eliminates "Address already in use" error from bind. */
        if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
                       (const void *)&optval , sizeof(int)) < 0)
            return -1;
       
        /* Listenfd will be an endpoint for all requests to port
           on any IP address for this host */
        bzero((char *) &serveraddr, sizeof(serveraddr));
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
        serveraddr.sin_port = htons((unsigned short)port);
        if (bind(listenfd, (SA *)&serveraddr, sizeof(serveraddr)) < 0)
            return -1;
       
        /* Make it a listening socket ready to accept connection requests */
        if (listen(listenfd, LISTENQ) < 0)
            return -1;
        return listenfd;
    }
    /* $end open_listenfd */
       
    /******************************************
     * Wrappers for the client/server helper routines
     ******************************************/
    int Open_clientfd(char *hostname, int port)
    {
        int rc;
       
        if ((rc = open_clientfd(hostname, port)) < 0)
        {
            if (rc == -1)
                unix_error("Open_clientfd Unix error");
            else
                dns_error("Open_clientfd DNS error");
        }
        return rc;
    }
       
    int Open_listenfd(int port)
    {
        int rc;
       
        if ((rc = open_listenfd(port)) < 0)
            unix_error("Open_listenfd error");
        return rc;
    }
    /* $end csapp.c */

     

  • 相关阅读:
    vue.js环境的搭建
    图片上传简单demo及springboot上传图片
    mybatise 模糊查询
    thymeleaf th:onclick 传参
    thymeleaf的特殊属性赋值
    无限分类的设计及前后台代码
    mysql 多个属性排序查询
    java添加对象成功后想知道当前添加对象的id
    SpringBoot2.x集成MQTT实现消息推送
    linux下安装MQTT服务器
  • 原文地址:https://www.cnblogs.com/kevinf/p/3706631.html
Copyright © 2011-2022 走看看