CSAPP(CMU 15-213):Lab7 proxylab详解

# 前言

本系列文章意在记录答主学习CSAPP Lab的过程,也旨在可以帮助后人一二,欢迎大家指正!


tips:完成一个 Web proxy(代码服务器、并发服务器、可以缓存)

Implementation

基本思想就是tiny serverecho server的结合,我因为之前不熟悉网络编程,所以把这两部分的示例代码重写了一遍,熟悉了一下。

tips:

  • 信号SIGPIPE
  • 依照handout的要求重新改写HTTP request headers

Part I: Implementing a sequential web proxy

代码proxy.c

#include <stdio.h>
#include "csapp.h"

/* Recommended max cache and object sizes */
#define MAX_CACHE_SIZE 1049000
#define MAX_OBJECT_SIZE 102400

static void parse_uri(char *uri, char *hostname, char *port, char *filepath);
static void build_request_header(rio_t *rp, char *reqhd, char *hostname);
void *thread(void *vargp);

/* You won't lose style points for including this long line in your code */
static const char *user_agent_hdr = "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.3) Gecko/20120305 Firefox/10.0.3\r\n";

static void doit(int fd);

int main(int argc, char **argv)
{
    char *server_port;
    int listenfd, *connfdp;
    socklen_t clientlen;
    struct sockaddr_storage clientaddr;
    char hostname[MAXLINE], port[MAXLINE];
    pthread_t tid;

    if (argc != 2) {
        fprintf(stderr, "usage: %s <port>\n", argv[0]);
        exit(0);
    }
    Signal(SIGPIPE, SIG_IGN);

    server_port = argv[1];
    listenfd = Open_listenfd(server_port);
    
    while (1) {
        clientlen = sizeof(struct sockaddr_storage);
        connfdp = Malloc(sizeof(int));
        *connfdp = Accept(listenfd, (SA *) &clientaddr, &clientlen);
        
        Getnameinfo((SA *) &clientaddr, clientlen, hostname, MAXLINE, port, MAXLINE, 0);
        printf("\nAccepted connection from (%s, %s) in proxy.\n", hostname, port);

        Pthread_create(&tid, NULL, thread, connfdp);

    }
    return 0;
}

void *thread(void *vargp) {
    int connfd = *((int *)vargp);
    Pthread_detach(pthread_self());
    Free(vargp);
    doit(connfd);
    Close(connfd);
    return NULL;
}
//handle HTTP request
static void doit(int serverfd) 
{
    rio_t rio_server;  //make proxy as server
    rio_t rio_client;  //make proxy as client
    char buf[MAXLINE];
    char method[MAXLINE], uri[MAXLINE], version[MAXLINE];
    char hostname[MAXLINE], filepath[MAXLINE], server_port[MAXLINE];
    int clientfd;
    char reqhd[MAXLINE];

    Rio_readinitb(&rio_server, serverfd);

    //handle HTTP request line
    if (!Rio_readlineb(&rio_server, buf, MAXLINE)) {

        return ;
    }
    sscanf(buf, "%s %s %s", method, uri, version);
    if (strcasecmp(method, "GET")) {   // only deal with "GET"
        return ;
    }
    if (!strcmp(version, "HTTP/1.1")) {
        strcpy(version, "HTTP/1.0");
    }

    parse_uri(uri, hostname, server_port, filepath);
    sprintf(uri, "%s %s %s\r\n", method, filepath, version);
    // build connect to web server
    clientfd = Open_clientfd(hostname, server_port);
    Rio_readinitb(&rio_client, clientfd);

    //read HTTP request from browser 
    strcpy(reqhd, uri);
    build_request_header(&rio_server, reqhd, hostname);
    //write HTTP headers to web server
    Rio_writen(clientfd, reqhd, strlen(reqhd));
    // send HTTP response to client browser
    ssize_t n;
    while ((n = Rio_readlineb(&rio_client, buf, MAXLINE))) {
        Rio_writen(serverfd, buf, n);
    }

    Close(clientfd);
}

//  eg. uri = http://localhost:4600/ 
static void parse_uri(char *uri, char *hostname, char *port, char *filepath)
{
    char *ptr1, *ptr2;
    uri += 7;
    ptr1 = index(uri, ':');    //default port is 80
    *ptr1 = '\0';
    ptr1++;
    strcpy(hostname, uri);

    ptr2 = index(ptr1, '/');
    *ptr2 = '\0';
    strcpy(port, ptr1);
    strcpy(filepath, "/");
    strcat(filepath, ptr2+1);
}

static void build_request_header(rio_t *rp, char *reqhd, char *hostname) {
    char buf[MAXLINE];

    while (Rio_readlineb(rp, buf, MAXLINE) > 0) {
        if (!strcmp(buf, "\r\n")) break;
        if (strstr(buf,"Host:") != NULL) continue;
        if (strstr(buf,"User-Agent:") != NULL) continue;
        if (strstr(buf,"Connection:") != NULL) continue;
        if (strstr(buf,"Proxy-Connection:") != NULL) continue;

        strcat(reqhd, buf);
    }
    sprintf(buf, "Host: %s\r\n", hostname);
    strcat(reqhd, buf);
    sprintf(buf, "User-Agent: %s", user_agent_hdr);
    strcat(reqhd, buf);
    strcat(reqhd, "Connection: false\r\n");
    strcat(reqhd, "Proxy-Connection: false\r\n");
    strcat(reqhd, "\r\n");
}

测试结果:

$ curl -v --proxy http://localhost:4600 http://localhost:4500/
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 4600 (#0)
> GET http://localhost:4500/ HTTP/1.1
> Host: localhost:4500
> User-Agent: curl/7.58.0
> Accept: */*
> Proxy-Connection: Keep-Alive
> 
* HTTP 1.0, assume close after body
< HTTP/1.0 200 OK
< Server: Tiny Web Server
< Content-length: 120
< Content-type: text/html
< 
<html>
<head><title>test</title></head>
<body> 
<img align="middle" src="godzilla.gif">
Dave O'Hallaron
</body>
</html>
* Closing connection 0

Part II: Dealing with multiple concurrent requests

第二部分很简单,只要依照书上的并发服务器重写就好啦,代码已经在第一部分出现啦

评分:

$ ./driver.sh
*** Basic ***
Starting tiny on 7990
Starting proxy on 8086
1: home.html
   Fetching ./tiny/home.html into ./.proxy using the proxy
   Fetching ./tiny/home.html into ./.noproxy directly from Tiny
   Comparing the two files
   Success: Files are identical.
2: csapp.c
   Fetching ./tiny/csapp.c into ./.proxy using the proxy
   Fetching ./tiny/csapp.c into ./.noproxy directly from Tiny
   Comparing the two files
   Success: Files are identical.
3: tiny.c
   Fetching ./tiny/tiny.c into ./.proxy using the proxy
   Fetching ./tiny/tiny.c into ./.noproxy directly from Tiny
   Comparing the two files
   Success: Files are identical.
4: godzilla.jpg
   Fetching ./tiny/godzilla.jpg into ./.proxy using the proxy
   Fetching ./tiny/godzilla.jpg into ./.noproxy directly from Tiny
   Comparing the two files
   Success: Files are identical.
5: tiny
   Fetching ./tiny/tiny into ./.proxy using the proxy
   Fetching ./tiny/tiny into ./.noproxy directly from Tiny
   Comparing the two files
   Success: Files are identical.
Killing tiny and proxy
basicScore: 40/40

*** Concurrency ***
Starting tiny on port 2104
Starting proxy on port 16490
Starting the blocking NOP server on port 26940
Trying to fetch a file from the blocking nop-server
Fetching ./tiny/home.html into ./.noproxy directly from Tiny
Fetching ./tiny/home.html into ./.proxy using the proxy
Checking whether the proxy fetch succeeded
Success: Was able to fetch tiny/home.html from the proxy.
Killing tiny, proxy, and nop-server
concurrencyScore: 15/15

*** Cache ***
Starting tiny on port 10359
Starting proxy on port 32380
Fetching ./tiny/tiny.c into ./.proxy using the proxy
Fetching ./tiny/home.html into ./.proxy using the proxy
Fetching ./tiny/csapp.c into ./.proxy using the proxy
Killing tiny
Fetching a cached copy of ./tiny/home.html into ./.noproxy
Failure: Was not able to fetch tiny/home.html from the proxy cache.
Killing proxy
cacheScore: 0/15

totalScore: 55/70

Part III: Caching web objects

​ 最近太忙啦,所以这个第三部分就暂时先不写了,日后如果涉及到网络编程的时候再来重构一下代码~

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: CSAPP Proxy LabCMU计算机科学系的一项课程作业。该作业旨在通过设计和实现一个基于代理服务器的Web代理,让学生更好地理解计算机网络、操作系统和编程等方面的知识,提高他们的编程能力和问题解决能力。 在这个作业中,学生需要实现一个Web代理程序,该程序需要能够接受来自客户端的HTTP请求,并将请求转发到相应的Web服务器。代理程序需要能够处理HTTP请求的各种类型(GET、POST、PUT等),并且需要能够处理HTTP响应的各种错误码(404、500等)。代理程序还需要支持并发处理多个HTTP请求,以提高系统的效率。 在实现代理程序的过程中,学生需要掌握网络编程、多线程编程、Socket编程等技术,并且需要使用C语言实现代理程序。此外,还需要学生能够理解HTTP协议、代理服务器的工作原理以及Web应用的工作流程等相关知识。 总之,CSAPP Proxy Lab是一项非常有挑战性的作业,需要学生具备扎实的编程基础和网络知识。通过完成该作业,学生可以深入理解计算机网络、操作系统和编程等方面的知识,并提高自己的编程能力和问题解决能力。 ### 回答2: CSAPP Proxy Lab是Carnegie Mellon大学计算机科学的一项项目,旨在帮助学生深入了解计算机网络和代理服务器的工作原理以及如何开发高效的网络应用程序。 Proxy Server是一种应用程序,可以充当网络上的“中转站”,它可以通过代理服务器将客户端请求转发到目标服务器端,并将响应返回给客户端。Proxy Lab的任务是实现一个HTTP代理服务器,它需要能够从客户端接收请求,并将请求转发到目标服务器,然后将响应发送回客户端。 实现Proxy Lab需要掌握网络编程、多线程编程、缓存设计以及HTTP协议等知识。代理服务器需要支持并发处理多个客户端请求,以保证高效的网络传输。为了提高性能,代理服务器还需要对常见的网页、图片和视频进行缓存,避免重复请求。 除了上述技能外,实现Proxy Lab还需要良好的编程能力和团队合作精神。在实现Proxy Lab的过程中,学生需要与队友紧密协作,及时沟通、并发同步,以确保项目的顺利进行。 总之,CSAPP Proxy Lab是一项非常有挑战性的计算机网络应用项目,不仅要求学生充分理解TCP/IP协议、HTTP协议等基本概念,还需要具备优秀的编程和团队协作能力。完成该项目不仅可以提高学生的技能,也可以为日后工作和实际应用打下良好的基础。 ### 回答3: CSAPP Proxy Lab 是一个经典的计算机科学实验,它涵盖了计算机网络知识和系统编程技能。这个实验的主要目标是构建一个基本的 Web 代理服务器,该服务器能够处理 HTTP 请求,并在远程 Web 服务器上代表客户端处理这些请求。 在 Proxy Lab 中,学生需要实现一个基于事件驱动的 Web 代理服务器。该服务器使用 epoll 进行事件处理,可以同时处理多个连接和请求。代理服务器需要支持从客户端接收 HTTP 请求,并解析请求头,将请求发送到远程服务器,接收响应,并将响应发送回客户端。在此过程中,代理服务器需要支持请求过滤和转发,以及缓存功能。 重要的是,学生需要处理一些常见的 Web 代理挑战,例如连接重用、响应缓存、虚拟主机支持和负载均衡。通过完成 Proxy Lab 实验,学生将获得有关计算机系统编程和网络协议的深入知识,并获得实际构建 Web 代理服务器的经验。 总之,CSAPP Proxy Lab 是一个非常重要的实验,它可以帮助学生领会计算机网络和系统编程的核心概念。通过完成这个实验,学生将获得深入的理解和实践经验,从而更好地了解计算机系统和网络技术。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值