网站建设鼠标移动变颜色传奇176网页游戏
web/
2025/10/3 15:16:40/
文章来源:
网站建设鼠标移动变颜色,传奇176网页游戏,织梦和wordpress哪个seo好,竞价推广代运营企业前情提要#xff0c;如果看了书本#xff0c;这个lab难度不高#xff0c;但是如果不看书#xff0c;难度还是挺高的#xff0c;并且这个lab会用到cachelab中学到的东西#xff0c;需要阅读
第十章#xff1a;系统编程第十一章#xff1a;网络编程第十二章#xff1a;…
前情提要如果看了书本这个lab难度不高但是如果不看书难度还是挺高的并且这个lab会用到cachelab中学到的东西需要阅读
第十章系统编程第十一章网络编程第十二章并发
实验介绍
使用代理完成客户端和服务器的连接HTTP操作socket通信 接受客户端的连接读并分析请求将请求发送给服务器读取服务器的回应并将回应发送给对应的客户端 实现多线程的功能增加cache功能
测试
测试./driver.sh 50 15 15
第一部分实现一个顺序的网络代理
任务要求
最开始代理应该监听某个端口来等待连接的请求这个端口通过命令行给出一旦建立连接代理应该读取并解析请求。它需要确定这个请求是否发送了一个合法的HTTP请求如果这个请求合法则发送给服务器然后将服务器的response返回给客户
具体实现
main函数打开一个监听的描述符如果通过这个监听描述符accept成功了则打开了一个用于通信的描述符fd将fd作为doit的函数调用doitdoit函数与描述符b建立通信读取客户端发来的请求这个请求一定是以下两种形式之一 指定端口 GET http://www.cmu.edu:8080/hub/index.html HTTP/1.1固定端口80 GET http://www.cmu.edu/hub/index.html HTTP/1.1 将上面收到的请求分解主要是得到中间的url然后将url分解得到hostportpath以指定端口为例这三个分别是 www.cmu.edu8080/hub/index.html 根据上面得到的三个参数构建发往服务器的request这个request是HTTP格式具体实现上就把这个放到一个字符数组就行了每一行通过\r\n隔开并且最后要多一行\r\n由请求头和请求行组成实验文档要求格式如下 GET /hub/index.html HTTP/1.0Host: www.cmu.eduUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:10.0.3) Gecko/20120305 Firefox/10.0.3Connection: closeProxy-Connection: close 与服务器建立连接得到server_fd描述符将上面已经生成好的request发往服务器不断地读服务器返回的值写入fd文件描述符
#include csapp.h
#include stdio.h
#include stdlib.h
#include string.h
#include strings.h
#include unistd.h/* Recommended max cache and object sizes */
#define MAX_CACHE_SIZE 1049000
#define MAX_OBJECT_SIZE 102400
#define MAXLINE 8192/* You wont 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;typedef struct {char host[MAXLINE];char port[MAXLINE];char path[MAXLINE];
} URI;void cout_uri_format_error() { printf(wrong uri format\n); }void parse_line(URI *req_uri, char *uri) {char *host_start strstr(uri, ://);if (host_start NULL) {cout_uri_format_error();return;}host_start 3;char *port_start strstr(host_start, :);char *path_start strstr(host_start, /);if (path_start NULL) {cout_uri_format_error();return;}strcpy(req_uri-path, path_start);*path_start \0;if (port_start ! NULL) {strcpy(req_uri-port, port_start 1);*port_start \0;} else {strcpy(req_uri-port, 80);}strcpy(req_uri-host, host_start);return;
}void build_req_server(char *req_server, URI *req_uri) {sprintf(req_server, GET %s HTTP/1.0\r\n, req_uri-path);sprintf(req_server, %sHost: %s\r\n, req_server, req_uri-host);sprintf(req_server, %s%s, req_server, user_agent_hdr);sprintf(req_server, %sConnection: close\r\n, req_server);sprintf(req_server, %sProxy-Connection: close\r\n, req_server);sprintf(req_server, %s\r\n, req_server);
}void doit(int fd) {// 初始化rio类函数的缓冲区rio_t rio;Rio_readinitb(rio, fd);// 读入这一行http请求char buf[MAXLINE];Rio_readlineb(rio, buf, MAXLINE);printf(Request headers:\n);printf(%s, buf);char method[MAXLINE], uri[MAXLINE], version[MAXLINE];// 解析这一行http请求总共三个部分if (sscanf(buf, %s %s %s, method, uri, version) ! 3) {printf(HTTP Requset Format Wrong!\n);return;}// 判断是否是GET请求这个比较函数忽略大小写get也行if (strcasecmp(method, GET)) {printf(method: %s not implemented\n, method);return;}// 至此已经完成了对客户端请求的解析接下来要构造出对服务器的请求// 首先解析我们的uri得到host port pathURI *req_uri (URI *)malloc(sizeof(URI));parse_line(req_uri, uri);// 根据我们的信息构造出真正的发往服务器的请求char req_server[MAXLINE];build_req_server(req_server, req_uri);// 开始连接服务器int server_fd Open_clientfd(req_uri-host, req_uri-port);if (server_fd 0) {printf(connection failed\n);return;}// 连接成功设置缓冲区将request写入rio_t server_rio;Rio_readinitb(server_rio, server_fd);Rio_writen(server_fd, req_server, strlen(req_server));// 等待服务器的返回并写入客户端的fd中size_t rec_bytes;while ((rec_bytes Rio_readlineb(server_rio, buf, MAXLINE)) ! 0) {printf(proxy received %d bytes\n, (int)rec_bytes);Rio_writen(fd, buf, rec_bytes);}Close(server_fd);
}int main(int argc, char **argv) {if (argc ! 2) {fprintf(stderr, usage: %s port\n, argv[0]);exit(1);}// 监听请求连接的端口int listenfd Open_listenfd(argv[1]);// 与客户端进行连接int connfd;char hostname[MAXLINE], port[MAXLINE];socklen_t clientlen;struct sockaddr_storage clientaddr;while (1) {clientlen sizeof(clientaddr);connfd Accept(listenfd, (SA *)(clientaddr), clientlen);Getnameinfo((SA *)(clientaddr), clientlen, hostname, MAXLINE, port,MAXLINE, 0);printf(Accepted connection from(%s,%s)\n, hostname, port);doit(connfd);Close(connfd);}return 0;
}
第二部分并发
任务要求
实现并发即可没有要求用什么样的方式
具体实现
采用生产者消费者的方式和书上第12.5.5节的代码几乎完全一样需要在main函数中加入一个Signal(SIGPIPE, SIG_IGN);以屏蔽SIGPIPE信号。我不太清楚不屏蔽会怎么样可能是不屏蔽的话客户端如果意外挂了会导致代理服务器一起挂了
#define SUBFSIZE 16
#define NTHREADS 4typedef struct {int *buf;int n;int front;int rear;sem_t mutex;sem_t slots;sem_t items;
} sbuf_t;sbuf_t sbuf;void sbuf_init(sbuf_t *sp, int n) {sp-buf Calloc(n, sizeof(int));sp-n n;sp-front sp-rear 0;Sem_init(sp-mutex, 0, 1);Sem_init(sp-slots, 0, n);Sem_init(sp-items, 0, 0);
}void sbuf_deinit(sbuf_t *sp) { Free(sp-buf); }void sbuf_insert(sbuf_t *sp, int item) {P(sp-slots);P(sp-mutex);sp-buf[(sp-rear) % (sp-n)] item;V(sp-mutex);V(sp-items);
}int sbuf_remove(sbuf_t *sp) {P(sp-items);P(sp-mutex);int item sp-buf[(sp-front) % (sp-n)];V(sp-mutex);V(sp-slots);return item;
}void *thread(void *vargp) {Pthread_detach(Pthread_self());while (1) {int connfd sbuf_remove(sbuf);doit(connfd);Close(connfd);}
}int main(int argc, char **argv) {if (argc ! 2) {fprintf(stderr, usage: %s port\n, argv[0]);exit(1);}// 监听请求连接的端口Signal(SIGPIPE, SIG_IGN);int listenfd Open_listenfd(argv[1]);// 线程池sbuf_init(sbuf, SUBFSIZE);pthread_t pid;for (int i 0; i NTHREADS; i) {Pthread_create(pid, NULL, thread, NULL);}// 与客户端进行连接int connfd;char hostname[MAXLINE], port[MAXLINE];socklen_t clientlen;struct sockaddr_storage clientaddr;while (1) {clientlen sizeof(clientaddr);connfd Accept(listenfd, (SA *)(clientaddr), clientlen);sbuf_insert(sbuf, connfd);}return 0;
}第三部分cache
任务要求
这里说是cache还不如说是一个大号的哈希表以uri为键以对应的资源为值。然后对这个哈希表的长度有点要求大概10个表项。因为题目要求#define MAX_CACHE_SIZE 1049000#define MAX_OBJECT_SIZE 102400其中object的意思就是一行差不多就是十倍的样子如果某个uri对应的资源太大了 那就不考虑加入cache对这个cahce需要实现并发访问即加上锁这里加入读写锁
具体实现
结合cachelab中cache的结构还需要额外加上data字段如果要实现真正的LRU在并发访问的基础上还需要对timestamp也加锁否则就要用原子类型的变量这个实现结合代码来看思路还是比较清晰的不再赘述 我在这里犯了两个小错结果导致debug了好久cacheline中的tag和data的长度是不一样的我一开始把data长度弄成了MAXLINE结果0分在doit中我们用uri去读cache以及写cache但是我们在doit的parse_line函数里是修改了uri的因此要给uri搞一个备份否则在写cache的时候就错了
/* Recommended max cache and object sizes */
#define MAX_CACHE_SIZE 1049000
#define MAX_OBJECT_SIZE 102400
#define MAXLINE 8192typedef struct {int is_valid;char tag[MAXLINE];char data[MAX_OBJECT_SIZE];long long access_time;int read_cnt;sem_t read_lock;sem_t write_lock;
} cacheline;#define MAX_CACHE_LINES 10
cacheline Cache[MAX_CACHE_LINES];sem_t time_mutex;
long long time_stamp 1;void init_cache() {for (int i 0; i MAX_CACHE_LINES; i) {Cache[i].is_valid 0;Cache[i].access_time 0;Cache[i].read_cnt 0;Sem_init(Cache[i].read_lock, 0, 1);Sem_init(Cache[i].write_lock, 0, 1);}Sem_init(time_mutex, 0, 1);
}void read_in(int i) {P(Cache[i].read_lock);if (Cache[i].read_cnt 0) {P(Cache[i].write_lock);}Cache[i].read_cnt;V(Cache[i].read_lock);
}void read_out(int i) {P(Cache[i].read_lock);if (Cache[i].read_cnt 1) {V(Cache[i].write_lock);}Cache[i].read_cnt--;V(Cache[i].read_lock);
}int read_cache(int fd, char *uri) {int flag 0;for (int i 0; i MAX_CACHE_LINES; i) {read_in(i);if (Cache[i].is_valid !strcmp(uri, Cache[i].tag)) {flag 1;P(time_mutex);Cache[i].access_time time_stamp;V(time_mutex);Rio_writen(fd, Cache[i].data, strlen(Cache[i].data));}read_out(i);if (flag) {return 0;}}return -1;
}void write_cache(char *uri, char *data) {int has_empty -1;int lru_evict 0;for (int i 0; i MAX_CACHE_LINES; i) {read_in(i);if (Cache[i].is_valid 0) {has_empty i;}if (Cache[i].access_time Cache[lru_evict].access_time) {lru_evict i;}read_out(i);if (has_empty ! -1) {break;}}int write_index (has_empty -1) ? lru_evict : has_empty;P(Cache[write_index].write_lock);Cache[write_index].is_valid 1;P(time_mutex);Cache[write_index].access_time time_stamp;V(time_mutex);strcpy(Cache[write_index].tag, uri);strcpy(Cache[write_index].data, data);V(Cache[write_index].write_lock);
}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/86280.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!