[lab] csapp-proxy

proxy lab

这个lab的解决方案还是相对直观的. 要求实现一个带内存缓存功能的http代理.

功能可以拆解为

  1. server
  2. client
  3. cache

一开始还有些疑惑, proxy server 只接受一个端口参数, 那如何知道转发给谁呢? 看到测试脚本使用 curl 才明白, 经过 --proxy 参数后, 虽然请求的目的地(包括第一行的uri 与 Host 头信息)还是 http server s, 但请求是发给 proxy server p 的.

大体的请求流程如下

没有proxy

c <--> s

proxy

  逻辑上请求
c ------- s
 \       /
  \     /
   \   /
     p

并且虽然 lab 要求中需要处理很多error case, 但实际给出 test case 并没有覆盖到, 再加上附带 tiny server 的例子, 如果只是追求过lab, 直接使用 csapp 里的 rio 等辅助函数就好.

proxy server

这里涉及到网络编程相关知识, 简要给出阶段1的骨干代码.

int main() {
  listen = Open_listenfd();
  // 循环接受请求
  while (client = accept(listen)) {
    handle_request(client);
  }
}

// 处理一次请求
int handle_request(client) {
  rio_t rio;

  http_header_map header_map;

  // 读取第一行
  read_line(client, buf);

  // method uri version

  // 解析 http 头
  header_map = read_headers(client);
  // 根据要求, 对一些 http header 进行修改
  rewrite_headers(header_map);

  // 打开请求的tcp client
  req_client = open_client(host);
  // 向其发送 http 头
  send_header(req_client, header_map);
  // 对两个 socket 的数据进行复制. 
  proxy_content(req_client, client);
}

这里我使用了自定义类型 http_header_map 用来吧所有 header 存起来统一处理, 也可以直接打开 http client, 处理完在线发送.

如果是存起来要注意 字符串的生命周期问题, 因为数据是存在本地buf中, 后面再读取buf就被覆盖了, 因此我们要malloc出来, 再拷贝.

其次是 uri 的解析, 虽然逻辑直观, c语言写起来还是挺麻烦的.

多线程

多线程要注意的问题还是 buf 的问题, 避免使用全局缓冲区, 使用函数本地缓存或与请求fd绑定就可以.

pthread_t thread;
Pthread_create(&thread, NULL, (void *(*)(void *))handle_request,
                (void *)connfd);
Pthread_detach(thread);

cache

cache 部分不要求我们完全按照http标准来控制, 算是简化了许多.

首先实现一个支持 lru的 cache struct, lru 其实已经在 cache lib 中实现过了, 这里不再赘述, 添加上缓存大小检查的代码即可.

然后是多线程访问 cache, 这里也使用最简单的 pthread_rwlock_t 来控制, 在 set 里加写锁, get 里先加读锁, 后加写锁更新访问时间.

最后是应用 cache, 逻辑如下

handle_request() {
  // 解析请求

  // 如果存在 cache, 就直接使用 cache 来响应.
  if (cache_item = cache_hit(uri)) {
    cache_serve(cache_item)
    return
  }
  // 否则创建新的 cache item 来保存结果, 
  cache_item = create_cache_item();
  client_serve(cache_item)
  // 写入cache中.
  cache_set(cache_item)
}
posted @ 2022-05-20 18:10  新新人類  阅读(227)  评论(0编辑  收藏  举报