【CSAPP】proxy Lab代理实验
来源:互联网 发布:java boolean几个字节 编辑:程序博客网 时间:2024/06/02 22:40
这个实验较为简单,但是要写出来还是得花一天半天的时间。主要实现到是一个代理的功能,接受客户端到请求,再代替客户端请求服务器相应的内容后,再返回给客户端。
多线程程序gdb调试:
1.info thread 显示当前有几个线程
2.thread num 转换到标号为num的线程,当前线程结束后,通过Ctrl+C返回前一个线程
下面直接贴上代码了,并且在文章的最后说明了对该代理程序如何进行调试。
#include "csapp.h"/* * Function prototypes */void parse_url(char *ur, char *hostname, char *query_path, int *port);void format_log_entry(char *logstring, struct sockaddr_in *sockaddr, char *uri, int size);void *thread(void *arg);void client_error(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg);int connect_server(char *hostname, int port, char *path );/* * varibles */struct args{ int fd; struct sockaddr_in sockaddr;};pthread_mutex_t mutex;FILE* logfile;/* * main - Main routine for the proxy program */int main(int argc, char **argv){ FILE* logfile; pthread_t tid; /* Check arguments */ if (argc != 2) {fprintf(stderr, "Usage: %s <port number>\n", argv[0]);exit(0); } Signal(SIGPIPE, SIG_IGN); logfile = Fopen("./logfile", "a"); int listenfd = Open_listenfd( atoi(argv[1]) ); while(1){ socklen_t len = sizeof(int); struct args* p = (struct args*)Malloc(sizeof(struct args)); p->fd = Accept(listenfd, (SA*)(&p->sockaddr),&len); Pthread_create(&tid, NULL, thread, p); } exit(1);}void *thread(void *arg){ rio_t rp; char buf[MAXLINE]; char method[MAXLINE]; char url[MAXLINE]; char version[MAXLINE]; char hostname[MAXLINE]; char path[MAXLINE]; int port; int serverfd; int clength; Pthread_detach(Pthread_self()); struct args* tmp = (struct args*)arg; int fd = tmp->fd; struct sockaddr_in sockaddr = tmp->sockaddr; Free(tmp); Rio_readinitb(&rp, fd); Rio_readlineb(&rp, buf, MAXLINE); if(sscanf(buf, "%s %s %s", method, url, version) < 3){ fprintf(stderr, "sscanf error"); client_error(fd, method, "404","Not Found", "Not Found"); Close(fd); return NULL; } if(strcmp(method,"GET")){ fprintf(stderr, "error request"); client_error(fd, method, "500","Not Implement", "Not Implement"); Close(fd); return NULL; } /*忽略首部和实体*/ do{ Rio_readlineb(&rp, buf, MAXLINE); }while(strcmp(buf, "\r\n")); /*解析URL,请求服务器*/ parse_url(url,hostname, path, &port); if( (serverfd = connect_server(hostname,port, path)) < 0){ Close(fd); return NULL; } /*等待读取服务器响应,并送回请求客户端*/ do{ Rio_readinitb(&rp, serverfd); Rio_readlineb(&rp, buf, MAXLINE); if(strstr(buf, "Content-length:")){ sscanf(buf, "Content-length: %d\r\n", &clength); Rio_writen(fd, buf, MAXLINE); } }while(strcmp(buf,"\r\n")); char logstring[MAXLINE]; pthread_mutex_lock(&mutex); format_log_entry(logstring, &sockaddr, url, clength); pthread_mutex_unlock(&mutex); fprintf(logfile, "%s\n", logstring); fflush(logfile); close(fd); close(serverfd);}int connect_server(char *hostname, int port, char *path ){ static const char *user_agent = "User-Agent: Mozilla (X11; Linux i386; rv:10.0.3) Gecko/20120305 Firefox/10.0.3\r\n"; 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"; static const char *connection = "Connection: close\r\nProxy-Connection: close\r\n"; char buf[MAXLINE]; /* connect to server */ int proxy_clientfd; proxy_clientfd=open_clientfd(hostname,port); /* if failed return */ if(proxy_clientfd<0) return proxy_clientfd; /* write request to server */ sprintf(buf,"GET %s HTTP/1.0\r\n", path); Rio_writen(proxy_clientfd,buf,strlen(buf)); sprintf(buf,"Host: %s\r\n",hostname); Rio_writen(proxy_clientfd,buf,strlen(buf)); Rio_writen(proxy_clientfd,user_agent,strlen(user_agent)); Rio_writen(proxy_clientfd,accept_str,strlen(accept_str)); Rio_writen(proxy_clientfd,connection,strlen(connection)); Rio_writen(proxy_clientfd,"\r\n",strlen("\r\n")); printf("request to server is done."); return proxy_clientfd;}/* parse request url */void parse_url(char *ur, char *hostname, char *query_path, int *port){ char url[100]; url[0]='\0'; strcat(url,ur); hostname[0]=query_path[0]='\0'; char *p=strstr(url,"//"); /* skip "http://" and "https://" */ if(p!=NULL) { p=p+2; } else { p=url; } char *q=strstr(p,":"); /* read ":<port>" and "/index.html" */ if(q!=NULL) { *q='\0'; sscanf(p,"%s",hostname); sscanf(q+1,"%d%s",port,query_path); } else { q=strstr(p,"/"); if(q!=NULL) { *q='\0'; sscanf(p,"%s",hostname); *q='/'; sscanf(q,"%s",query_path); } else { sscanf(p,"%s",hostname); } *port=80; } /* the default path */ if(strlen(query_path)<=1) strcpy(query_path,"/index.html"); return;}/* * format_log_entry - Create a formatted log entry in logstring. * * The inputs are the socket address of the requesting client * (sockaddr), the URI from the request (uri), and the size in bytes * of the response from the server (size). */void format_log_entry(char *logstring, struct sockaddr_in *sockaddr, char *uri, int size){ time_t now; char time_str[MAXLINE]; unsigned long host; unsigned char a, b, c, d; /* Get a formatted time string */ now = time(NULL); strftime(time_str, MAXLINE, "%a %d %b %Y %H:%M:%S %Z", localtime(&now)); /* * Convert the IP address in network byte order to dotted decimal * form. Note that we could have used inet_ntoa, but chose not to * because inet_ntoa is a Class 3 thread unsafe function that * returns a pointer to a static variable (Ch 13, CS:APP). */ host = ntohl(sockaddr->sin_addr.s_addr); a = host >> 24; b = (host >> 16) & 0xff; c = (host >> 8) & 0xff; d = host & 0xff; /* Return the formatted log entry string */ sprintf(logstring, "%s: %d.%d.%d.%d %s", time_str, a, b, c, d, uri);}void client_error(int fd, char *cause, char *errnum, char *shortmsg, char *longmsg) { char buf[MAXLINE], body[MAXBUF]; /* Build the HTTP response body */ sprintf(body, "%s: %s\r\n", errnum, shortmsg); sprintf(body, "%s%s: %s", body, longmsg, cause); /* Print the HTTP response */ sprintf(buf, "HTTP/1.0 %s %s\r\n", errnum, shortmsg); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-type: text/html\r\n"); Rio_writen(fd, buf, strlen(buf)); sprintf(buf, "Content-length: %d\r\n\r\n", (int)strlen(body)); Rio_writen(fd, buf, strlen(buf)); Rio_writen(fd, body, strlen(body));}
如何调试本程序:使用nc这个小巧的工具,常见用法自行man。
在这里我们先选择一个空闲到端口,并在一个终端执行以下命令:
nc -l 5000此命令使得nc作为端口5000的监听服务器,可以接受信息。
然后我们再选择一个空闲端口运行代理程序:
./proxy 10000 &接着,我们使用curl这个工具模拟客户端产生HTTP请求:
curl -v -proxy http://127.0.0.1:10000/ http://127.0.0.1:500/
此时我们便能看到服务器接收到我们客户端发出的请求了。
1 0
- 【CSAPP】proxy Lab代理实验
- CSAPP LAB---Proxy lab
- CSAPP: Proxy lab
- CSAPP LAB---MALLOC实验
- csapp bomb lab:csapp lab2 炸弹实验
- 【CSAPP】Shell Lab 外壳实验
- CSAPP实验2:Bomb Lab
- csapp 实验 Cache Lab: Understanding Cache Memories
- CSAPP LAB---buflab-handout(缓冲区溢出实验)
- CSAPP LAB---buflab-handout(缓冲区溢出实验)
- CSAPP:Attack Lab —— 缓冲区溢出攻击实验
- CSAPP: bomb lab
- CSAPP: buffer lab
- CSAPP: shell lab
- CSAPP: malloc lab
- CSAPP LAB---shlab-handout
- 【CSAPP】malloc Lab
- CSAPP Data Lab
- Label Button和textfield组合
- test
- jdbc-odbc连接dbf (转)
- uva11732 字典树
- MATLAB 无约束一维极值问题
- 【CSAPP】proxy Lab代理实验
- 双向冒泡排序
- SQL语句执行效率及分析
- Linux下实现简单Echo中继服务器
- unity3d中的local和global
- 排序分类基本介绍
- 树与二叉树
- 设计模式—单例模式(Singleton pattern)
- ST算法