首页 > 代码库 > CSAPP2e: Proxy lab 解答

CSAPP2e: Proxy lab 解答

  这次的Proxy lab 是要求实现一个简单的web 代理。与此相关的章节是网络编程和并发编程,其实之前零零星星的看过一些讲HTTP协议的书,但是对于套接字这些都是一知半解,跟着课堂学完这两章突然柳暗花明,再看一些更详细更深入的书,像《HTTP权威指南》,《计算机网络-自顶向下的方法》就明白的多了。

  下面就说一下这次lab,共有3个部分,第一部分是实现一个单线程代理,接收客户端请求,连接服务器然后转发。第二部分是实现并发,为每一个请求新建一个进程。第三部分是最有趣的,为每个请求建立独立的进程之后,该怎么共享进程之间的数据,也就是缓存呢?这里用到了书上介绍的写者-读者模型。源代码如下(已经通过了测试)。

 

  1 /*  2  * justforyeah@yeah.net  3  * 2014.12.28 18:24  4  */  5   6 #include "csapp.h"  7   8 #define MAX_CACHE_SIZE 1049000  9 #define MAX_OBJECT_SIZE 102400 10  11 /* argument for each thread */ 12 struct arg { 13     int connfd;            /* client socked */ 14     int turn;            /* the time of current request */ 15 }; 16 /* cache block */ 17 struct cache_block { 18     char data[MAX_OBJECT_SIZE];        /* store the response head and body */ 19     sem_t mutex;                    /* 模仿书上P673,使用写者-读者模型解决并发冲突 */ 20     sem_t w; 21     int readcnt; 22  23     int turn;                        /* the time of request */ 24     sem_t t_mutex;                 25     sem_t t_w; 26     int t_readcnt; 27  28     char url[300];                    /* the url of request */ 29     sem_t url_mutex; 30     sem_t url_w; 31     int url_readcnt; 32  33 }; 34 /* total 10 cache block */ 35 struct cache_block cache[10]; 36  37 /* init the block */ 38 void cache_erase(int index); 39  40 /* because of concurrency, all operation on cache use following 4 function */ 41 /* write data, url and turn on cache[index] */ 42 void cache_write(int index, char *url,char *data, int turn); 43 /* read data on cache[index] */ 44 void cache_data_read(int index, char *dst, int turn); 45 /* read url on cache[index] */ 46 void cache_url_read(int index,char *dst); 47 /* read turn on cache[index] */ 48 int cache_turn_read(int index); 49  50 /* thread for each request */ 51 void *thread(void *connfdp); 52  53 /* parse the request line */ 54 void parse_url(char *url, char *hostname, char *query_path, int *port); 55  56 /* connect to server, if failed return -1 */ 57 int connect_server(char *hostname,int port,char *query_path); 58  59  60 int main(int argc,char **argv) 61 { 62     Signal(SIGPIPE, SIG_IGN); 63     struct sockaddr_in clientaddr; 64     int port,listenfd,clientlen; 65     int turn=1; 66     pthread_t tid; 67     struct arg *p; 68  69     /* check port */ 70     if(argc!=2) { 71         fprintf(stderr, "usage: %s <port>\n", argv[0]); 72         exit(0); 73     } 74  75     // init 10 cache blocks 76     int i; 77     for(i=0;i<10;i++) 78         cache_erase(i); 79  80     port=atoi(argv[1]); 81     listenfd=Open_listenfd(port); 82     clientlen=sizeof(clientaddr); 83  84     while(1) { 85         p=(int*)Malloc(sizeof(struct arg)); 86         p->connfd=Accept(listenfd,(SA*)&clientaddr,&clientlen); 87         p->turn =turn++; 88         /* create thread */ 89         Pthread_create(&tid,NULL,thread,(void *)p); 90     } 91     return 0; 92 } 93  94 /* parse request url */ 95 void parse_url(char *ur, char *hostname, char *query_path, int *port) 96 { 97     char url[100]; 98     url[0]=\0; 99     strcat(url,ur);100     hostname[0]=query_path[0]=\0;101     char *p=strstr(url,"//");        /* skip "http://" and "https://" */102     if(p!=NULL) {103         p=p+2;104     } else {105         p=url;106     }107     char *q=strstr(p,":");            /* read ":<port>" and "/index.html" */108     if(q!=NULL) {109         *q=\0;110         sscanf(p,"%s",hostname);111         sscanf(q+1,"%d%s",port,query_path);112     } else {113         q=strstr(p,"/");114         if(q!=NULL) {115             *q=\0;116             sscanf(p,"%s",hostname);117             *q=/;118             sscanf(q,"%s",query_path);119         } else {120             sscanf(p,"%s",hostname);121         }122         *port=80;123     }124     /* the default path */125     if(strlen(query_path)<=1)126         strcpy(query_path,"/index.html");127 128     return;129 }130 131 /* connect to server and return socket fd */132 int connect_server(char *hostname,int port,char *query_path)133 {134     static const char *user_agent = "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.3) Gecko/20120305 Firefox/10.0.3\r\n";135     static const char *accept_str= "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate\r\n";136     static const char *connection = "Connection: close\r\nProxy-Connection: close\r\n";137     138     char buf[MAXLINE];139     /* connect to server */140     int proxy_clientfd;141     proxy_clientfd=open_clientfd(hostname,port);142 143     /* if failed return */144     if(proxy_clientfd<0)145         return proxy_clientfd;146 147     /* write request to server */148     sprintf(buf,"GET %s HTTP/1.0\r\n",query_path);149     Rio_writen(proxy_clientfd,buf,strlen(buf));150     sprintf(buf,"Host: %s\r\n",hostname);151     Rio_writen(proxy_clientfd,buf,strlen(buf));152     Rio_writen(proxy_clientfd,user_agent,strlen(user_agent));153     Rio_writen(proxy_clientfd,accept_str,strlen(accept_str));154     Rio_writen(proxy_clientfd,connection,strlen(connection));155     Rio_writen(proxy_clientfd,"\r\n",strlen("\r\n"));156     return proxy_clientfd;157 }158 159 /*160  * if there is a finished cache, read and response.161  * else connect to server162  */163 void *thread(void *p)164 {165     Pthread_detach(pthread_self());166     int connfd=((struct arg*)p)->connfd,turn=((struct arg*)p)->turn;167     free(p);168 169     char buf[MAXLINE];170     char method[MAXLINE],version[MAXLINE],url[MAXLINE];171     char host[MAXLINE],query[MAXLINE];172     char url_tmp[300],*data_tmp;173     rio_t rio;174     int index,port,content_length;175     int serverfd;176 177     /* read request line */178     rio_readinitb(&rio,connfd);179     rio_readlineb(&rio,buf,MAXLINE);180     sscanf(buf,"%s %s %s",method,url,version);181 182     if(strcasecmp(method,"GET")) {183         /* ignore */184         printf("Not GET\r\n");185         Close(connfd);186         return NULL;187     }188     /* ignore client request */189     do {190         rio_readlineb(&rio,buf,MAXLINE-1);191     }while(strcmp(buf,"\r\n"));192 193     /* find cache block */194     for(index=0;index<10;index++) {195         cache_url_read(index,url_tmp);196         /* the block‘url is same as current url */197         if(!strcmp(url,url_tmp))198             break;199     }200 201     data_tmp=(char*)Malloc(MAX_OBJECT_SIZE);202     data_tmp[0]=\0;203 204     if(index <10) { /* if have cached */205         cache_data_read(index,data_tmp,turn);206         rio_writen(connfd,data_tmp,strlen(data_tmp));207         Close(connfd);208         free(data_tmp);209         return NULL;210     }211 212     /* connect to server */213     parse_url(url,host,query,&port);214     if((serverfd=connect_server(host,port,query))<0) {215         /* connect to server failed, return */216         free(data_tmp);217         Close(connfd);218         return NULL;219     }220 221     rio_readinitb(&rio,serverfd);222     content_length=0;223     /* read response head line */224     do {225         int t=rio_readlineb(&rio,buf,MAXLINE-1);226         if(t<=0)227             break;228         strncat(data_tmp,buf,t);229         if(strstr(buf,"Content-length")!=NULL)230             sscanf(buf,"Content-length: %d\r\n",&content_length);231         rio_writen(connfd,buf,t);232     }while(strcmp(buf,"\r\n"));233 234     /* read response body */235     /* response is small enough to cache */236     if(content_length+strlen(data_tmp)<MAX_OBJECT_SIZE) {237         while(content_length>0) {238             int t= rio_readnb(&rio,buf,(content_length<MAXLINE-1)?content_length:MAXLINE-1);239             if(t<=0)240                 continue;241             content_length-=t;242             strncat(data_tmp,buf,t);243             rio_writen(connfd,buf,t);244         }245         index=0;246         int i;247         /* least-recently-used */248         for(i=1;i<10;i++) {249             if(cache_turn_read(i)<cache_turn_read(index)) {250                 index=i;251             }252         }253         /* cache write */254         cache_write(index,url,data_tmp,turn);255     }256     /* ignore store and write to client */257     else {258         while(content_length>0) {259             int t= rio_readnb(&rio,buf,(content_length<MAXLINE-1)?content_length:MAXLINE-1);260             if(t<=0)261                 break;262             content_length-=t;263             rio_writen(connfd,buf,t);264         }265     }266     Close(connfd);267     Close(serverfd);268     free(data_tmp);269     return NULL;270 }271 272 void cache_erase(int index)273 {274     /* init all var */275     cache[index].turn=0;    276     cache[index].url[0]=\0;277     cache[index].data[0]=\0;278     Sem_init(&cache[index].t_mutex,0,1);279     Sem_init(&cache[index].t_w,0,1);280     cache[index].t_readcnt=0;281     Sem_init(&cache[index].url_mutex,0,1);282     Sem_init(&cache[index].url_w,0,1);283     cache[index].url_readcnt=0;284     Sem_init(&cache[index].mutex,0,1);285     Sem_init(&cache[index].w,0,1);286     cache[index].readcnt=0;287 }288 289 void cache_write(int index,char *url, char *data, int turn)290 {291     /* semaphore */292     P(&cache[index].url_w);293     P(&cache[index].w);294     P(&cache[index].t_w);295     /* begin write operation */296     cache[index].turn=turn;297     strcpy(cache[index].data,data);298     strcpy(cache[index].url,url);299     /* end write operation */300 301     /* semaphore */302     V(&cache[index].t_w);303     V(&cache[index].w);304     V(&cache[index].url_w);305     return ;306 }307 308 void cache_data_read(int index, char *dst, int turn)309 {310     /* semaphore */311     P(&cache[index].mutex);312     cache[index].readcnt++;313     if(cache[index].readcnt==1)314         P(&cache[index].w);315     V(&cache[index].mutex);316     P(&cache[index].t_w);317 318     /* begin read operation */319     cache[index].turn=turn;320     strcpy(dst,cache[index].data);321     /* end read operation */322 323     /* semphore */324     V(&cache[index].t_w);325     P(&cache[index].mutex);326     cache[index].readcnt--;327     if(cache[index].readcnt==0)328         V(&cache[index].w);329     V(&cache[index].mutex);330 331     return;332 }333 334 void cache_url_read(int index,char *dst)335 {336     /* semaphore */337     P(&cache[index].url_mutex);338     cache[index].url_readcnt++;339     if(cache[index].url_readcnt==1)340         P(&cache[index].url_w);341     V(&cache[index].url_mutex);342 343     /* begin read operation */344     strcpy(dst,cache[index].url);345     /* end read operation */346 347     /* semphore */348     P(&cache[index].url_mutex);349     cache[index].url_readcnt--;350     if(cache[index].url_readcnt==0)351         V(&cache[index].url_w);352     V(&cache[index].url_mutex);353 354     return;355 }356 357 int cache_turn_read(int index)358 {359     int t;360     /* semaphore */361     P(&cache[index].t_mutex);362     cache[index].t_readcnt++;363     if(cache[index].t_readcnt==1)364         P(&cache[index].t_w);365     V(&cache[index].t_mutex);366 367     /* begin read operation */368     t=cache[index].turn;369     /* end read operation */370 371     /* semphore */372     P(&cache[index].t_mutex);373     cache[index].t_readcnt--;374     if(cache[index].t_readcnt==0)375         V(&cache[index].t_w);376     V(&cache[index].t_mutex);377 378     return t;379 }

 

CSAPP2e: Proxy lab 解答