这次的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> ", 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]='