zoukankan      html  css  js  c++  java
  • 实验四Web服务器2

    Web服务器

    1.任务详情

    基于华为鲲鹏云服务器CentOS中(或Ubuntu),使用Linux Socket实现:

    1. Web服务器的客户端服务器,提交程序运行截图
    2. 实现GET即可,请求,响应要符合HTTP协议规范
    3. 服务器部署到华为云服务器,浏览器用本机的
    4. 把服务器部署到试验箱。(加分项)

    2.实验过程

    代码部分直接使用了老师提供的代码,更改了部分地址位置与参数成功运行
    copy.c

    #include <stdio.h>
    
    static char copybuf[16384];
    
    extern int TIMEOUT;
    
    int copy(FILE *read_f, FILE *write_f)
    {
      int n;
      int wrote;
      alarm(TIMEOUT);
      while (n = fread(copybuf,1,sizeof(copybuf),read_f)) {
        alarm(TIMEOUT);
        wrote = fwrite(copybuf,n,1,write_f);
        alarm(TIMEOUT);
        if (wrote < 1)
        	return -1;
      }
      alarm(0);
      return 0;
    }
    

    httpd.c

    #include <stdio.h>
    #include <stdlib.h>
    #include <fcntl.h>
    #include <string.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <errno.h>
    #include <sys/stat.h>
    #include <dirent.h>
    #include <signal.h>
    #include <unistd.h>
    #include <ctype.h>
    #include "pthread.h"
    
    #define DEBUG
    
    int KEY_QUIT=0;
    int TIMEOUT=30;
    
    #ifndef O_BINARY
    #define O_BINARY 0
    #endif
    
    char referrer[128];
    int content_length;
    
    #define SERVER_PORT 80
    
    int PrintHeader(FILE *f, int content_type)
    {
      alarm(TIMEOUT);
      fprintf(f,"HTTP/1.0 200 OK\n");
      switch (content_type)
      { 
       case 't':
        fprintf(f,"Content-type: text/plain\n");
        break;
       case 'g':
        fprintf(f,"Content-type: image/gif\n");
        break;
       case 'j':
        fprintf(f,"Content-type: image/jpeg\n");
        break;
       case 'h':
        fprintf(f,"Content-type: text/html\n");
        break;
      }
      fprintf(f,"Server: uClinux-httpd 0.2.2\n");
      fprintf(f,"Expires: 0\n");
      fprintf(f,"\n");
      alarm(0);
      return(0);
    }
    
    int DoJpeg(FILE *f, char *name)
    {
      char *buf;
      FILE * infile;
      int count;
     
      if (!(infile = fopen(name, "r"))) {
        alarm(TIMEOUT);
        fprintf(stderr, "Unable to open JPEG file %s, %d\n", name, errno);
        fflush(f);
        alarm(0);
        return -1;
      }
     
      PrintHeader(f,'j');	
    
     
      copy(infile,f); /* prints the page */
     
      alarm(TIMEOUT);
      fclose(infile);
      alarm(0);
     
      return 0;
    }
    
    int DoGif(FILE *f, char *name)
    {
      char *buf;
      FILE * infile;
      int count;
    
      if (!(infile = fopen(name, "r"))) {
        alarm(TIMEOUT);
        fprintf(stderr, "Unable to open GIF file %s, %d\n", name, errno);
        fflush(f);
        alarm(0);
        return -1;
      }
      
      PrintHeader(f,'g');
    
      copy(infile,f); /* prints the page */  
    
      alarm(TIMEOUT);
      fclose(infile);
      alarm(0);
      
      return 0;
    }
    
    int DoDir(FILE *f, char *name)
    {
      char *buf;
      DIR * dir;
      struct dirent * dirent;
    
      if ((dir = opendir(name))== 0) {
        fprintf(stderr, "Unable to open directory %s, %d\n", name, errno);
        fflush(f);
        return -1;
      }
      
      PrintHeader(f,'h');
      
      alarm(TIMEOUT);
      fprintf(f, "<H1>Index of %s</H1>\n\n",name);
      alarm(0);
    
      if (name[strlen(name)-1] != '/') {
    	strcat(name, "/");
      }
      
      while(dirent = readdir(dir)) {
    	alarm(TIMEOUT);
      
    	fprintf(f, "<p><a href=\"/%s%s\">%s</a></p>\n", name, dirent->d_name, dirent->d_name);
    	alarm(0);
      }
      
      closedir(dir);
      return 0;
    }
    
    int DoHTML(FILE *f, char *name)
    {
      char *buf;
      FILE *infile;
      int count;
      char * dir = 0;
    
      if (!(infile = fopen(name,"r"))) {
        alarm(TIMEOUT);
        fprintf(stderr, "Unable to open HTML file %s, %d\n", name, errno);
        fflush(f);
        alarm(0);
        return -1;
      }
    
      PrintHeader(f,'h');
      copy(infile,f); /* prints the page */  
    
      alarm(TIMEOUT);
      fclose(infile);
      alarm(0);
    
      return 0;
    }
    
    int DoText(FILE *f, char *name)
    {
      char *buf;
      FILE *infile;
      int count;
    
      if (!(infile = fopen(name,"r"))) {
        alarm(TIMEOUT);
        fprintf(stderr, "Unable to open text file %s, %d\n", name, errno);
        fflush(f);
        alarm(0);
        return -1;
      }
    
      PrintHeader(f,'t');
      copy(infile,f); /* prints the page */  
    
      alarm(TIMEOUT);
      fclose(infile);
      alarm(0);
    
      return 0;
    }
    
    int ParseReq(FILE *f, char *r)
    {
      	char *bp;
      	struct stat stbuf;
      	char * arg;
      	char * c;
      	int e;
      	int raw;
    
    #ifdef DEBUG
      	printf("req is '%s'\n", r);
    #endif
      
      	while(*(++r) != ' ');  /*skip non-white space*/
      	while(isspace(*r))
      		r++;
      
      	while (*r == '/')
      		r++;
      	bp = r;
      
      	while(*r && (*(r) != ' ') && (*(r) != '?'))
      		r++;
      	
    #ifdef DEBUG
      	printf("bp='%s' %x, r='%s' \n", bp, *bp,r);
    #endif
      	
      	if (*r == '?')
      	{
      		char * e;
      		*r = 0;
      		arg = r+1;
      		if (e = strchr(arg,' ')) 
    		{
      			*e = '\0';
      		}
      	} else 
        {
      		arg = 0;
    	  	*r = 0;
        }
      
      	c = bp;
    
    /*zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz*/    
      	if (c[0] == 0x20){
    		c[0]='.';
    		c[1]='\0'; 
    	}
    /*zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz*/    
    	if(c[0] == '\0') strcat(c,".");
    		
    	if (c && !stat(c, &stbuf)) 
      	{
        	if (S_ISDIR(stbuf.st_mode)) 
        	{ 
        		char * end = c + strlen(c);
        		strcat(c, "/index.html");
        		if (!stat(c, &stbuf)) 
            	{
        			DoHTML(f, c);
        		} 
            	else 
            	{
      				*end = '\0';
    				DoDir(f,c);
    			}
        	}
        	else if (!strcmp(r - 4, ".gif"))
          		DoGif(f,c);
            else if (!strcmp(r - 4, ".jpg") || !strcmp(r - 5, ".jpeg"))
              	DoJpeg(f,c);
            else if (!strcmp(r - 4, ".htm") || !strcmp(r - 5, ".html"))
                DoHTML(f,c);
                 else
                      DoText(f,c);
    	} 
    	else{
    	  	PrintHeader(f,'h');
      		alarm(TIMEOUT);
    	  	fprintf(f, "<html><head><title>404 File Not Found</title></head>\n");
    		fprintf(f, "<body>The requested URL was not found on this server</body></html>\n");
    	  	alarm(0);
        }
      	return 0;
    }
    
    void sigalrm(int signo)
    {
    	/* got an alarm, exit & recycle */
    	exit(0);
    }
    
    int HandleConnect(int fd)
    {
      FILE *f;
    
      char buf[160];
      char buf1[160];
    
      f = fdopen(fd,"a+");
      if (!f) {
        fprintf(stderr, "httpd: Unable to open httpd input fd, error %d\n", errno);
        alarm(TIMEOUT);
        close(fd);
        alarm(0);
        return 0;
      }
      setbuf(f, 0);
    
      alarm(TIMEOUT);
    
      if (!fgets(buf, 150, f)) {
        fprintf(stderr, "httpd: Error reading connection, error %d\n", errno);
        fclose(f);
        alarm(0);
        return 0;
      }
    #ifdef DEBUG
      	printf("buf = '%s'\n", buf);
    #endif
        
      	alarm(0);
    
      	referrer[0] = '\0';
      	content_length = -1;
        
     	alarm(TIMEOUT);
    	//read other line to parse Rrferrer and content_length infomation
    	while (fgets(buf1, 150, f) && (strlen(buf1) > 2)) {
      		alarm(TIMEOUT);
    		#ifdef DEBUG
    	    	printf("Got buf1 '%s'\n", buf1);
    		#endif
        	if (!strncasecmp(buf1, "Referer:", 8)) {
    	      	char * c = buf1+8;
        	  	while (isspace(*c))
    				c++;
    		    strcpy(referrer, c);
        	} 
        	else if (!strncasecmp(buf1, "Referrer:", 9)) {
          		char * c = buf1+9;
         		 while (isspace(*c))
    				c++;
          		strcpy(referrer, c);
        	} 
        	else if (!strncasecmp(buf1, "Content-length:", 15)) {
          		content_length = atoi(buf1+15);
        	} 
      	}
      	alarm(0);
      
      	if (ferror(f)) {
        	fprintf(stderr, "http: Error continuing reading connection, error %d\n", errno);
    	    fclose(f);
        	return 0;
      	}	
        
      	ParseReq(f, buf);
    
      	alarm(TIMEOUT);
      	fflush(f);
      	fclose(f);
      	alarm(0);
      	return 1;
    }
    
    
    
    void* key(void* data)
    {
    	int c;
    	for(;;){
    		c=getchar();	
    		if(c == 'q' || c == 'Q'){
    			KEY_QUIT=1;
    			exit(10);
    			break;
    		}
    	}
    		
    }
    
    int main(int argc, char *argv[])
    {
      int fd, s;
      int len;
      volatile int true = 1;
      struct sockaddr_in ec;
      struct sockaddr_in server_sockaddr;
    	  
      pthread_t th_key;
      void * retval;
    
    
      signal(SIGCHLD, SIG_IGN);
      signal(SIGPIPE, SIG_IGN);
      signal(SIGALRM, sigalrm);
    
      chroot(".");
      printf("starting httpd...\n");
      printf("press q to quit.\n");
    //  chdir("/");
    
      if (argc > 1 && !strcmp(argv[1], "-i")) {
        /* I'm running from inetd, handle the request on stdin */
        fclose(stderr);
        HandleConnect(0);
        exit(0);
      }
    
      if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
        perror("Unable to obtain network");
        exit(1);
      }
      
      if((setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&true, 
    		 sizeof(true))) == -1) {
        perror("setsockopt failed");
        exit(1);
      }
    
      server_sockaddr.sin_family = AF_INET;
      server_sockaddr.sin_port = htons(SERVER_PORT);
      server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY);
      
      if(bind(s, (struct sockaddr *)&server_sockaddr, 
    	  sizeof(server_sockaddr)) == -1)  {
        perror("Unable to bind socket");
        exit(1);
      }
    
      if(listen(s, 8*3) == -1) { /* Arbitrary, 8 files/page, 3 clients */
        perror("Unable to listen");
        exit(4);
      }
    
      
       	pthread_create(&th_key, NULL, key, 0);
      /* Wait until producer and consumer finish. */
      printf("wait for connection.\n");	
      while (1) {
    	  
        len = sizeof(ec);
        if((fd = accept(s, (void *)&ec, &len)) == -1) {
          exit(5);
          close(s);
        }
        HandleConnect(fd);
    	
      }
      pthread_join(th_key, &retval);
    }
    

    Makefile

    TOPDIR = /home/tzy/web/ws/07_httpd/
    include $(TOPDIR)Rules.mak
    EXTRA_LIBS += -lpthread
    
    EXEC = $(INSTALL_DIR)  ./httpd
    OBJS = httpd.o copy.o
    
    HTTPD_DOCUMENT_ROOT = /home/tzy/web/ws/07_httpd/
    CFLAGS += -DHTTPD_DOCUMENT_ROOT=\"$(HTTPD_DOCUMENT_ROOT)\"
    
    all: $(EXEC)
    
    $(EXEC): $(OBJS)
            $(CC) $(LDFLAGS) -o $@ $(OBJS) $(EXTRA_LIBS)
    
    
    install:
            $(EXP_INSTALL) $(EXEC) $(INSTALL_DIR)
    
    clean:
            -rm -f $(EXEC) *.elf *.gdb *.o
    

    Rules.mak

    TOPDIR= ..
    CROSS = arm-linux-
    CC= ${CROSS}gcc
    #CC=gcc
    #CFLAGS += -g
    #LDFLAGS += -static  
    EXTRA_LIBS +=
    EXP_INSTALL = install -m 755
    INSTALL_DIR = /home/tzy/web/ws/07_httpd/
    
    • 使用make命令导出可执行文件httpd,中间遇到的问题会在最后进行汇总

    • 但是发现软件无法执行,经查询发现是因为使用的是32bit的Ubuntu编译的

    • 重新调整,并更改了可执行文件名

    • 最后更新了tools工具,使用sudo dhclient进行联网,ipconfig查询地址发现地址为http://192.168.23.128/,实现结果如下



      代码链接:https://gitee.com/tang_zi_yue1927/code/tree/master/web/web/ws/07_httpd

    • 在华为云上使用同样步骤实现,并设置端口号为1327,实现截图如下


    3.问题汇总

    • 首先执行发现无法识别Rules.mak中CROSS部分的armv4l-unknown-linux-,经上网查询下载了另一交叉编译器arm-linux-gcc
      • 使用sudo tar -xjvf /home/tzy/arm-linux-gcc-4.6.4-arm-x86_64.tar.bz2 -C /对在网上下载的压缩包进行解压
      • 解压完成后,再在(/usr/local)中创建一个新目录arm,即在Terminal中输入以下命令:sudo mkdir /usr/local/arm (因为已经实现故文件存在)
      • 创建arm目录成功后,还需要给它解放全部权限,即在Terminal中输入以下命令:sudo chmod 777 /usr/local/arm
      • 在解压出来的目录中找到并把整个gcc-4.6.4目录复制到刚刚建好的arm目录中,先cd切换到gcc-4.6.4所在目录(切换后先ls看一下有没有gcc-4.6.4目录):
        cd /opt/TuxamitoSoftToolchains/arm-arm1176jzfssf-linux-gnueabi/
      • 再执行 cp 复制命令,-r 表示整个目录以及里面的任何东西sudo cp -r gcc-4.6.4 /usr/local/arm
      • 打开(/etc/profile)配置环境变量和库变量,目的是以后可以在任何位置使用该交叉编译器,命令如下:sudo vim /etc/profile
      • 用vim打开后,在文件最后添加两行,并输入以下代码:第一行是添加执行程序的环境变量,第二行是库文件的路径:
    1 export PATH=$PATH:/usr/local/arm/gcc-4.6.4/bin
    2 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/arm/gcc-4.6.4/lib
    


    - 使用source命令重新加载生效该配置文件source /etc/profile
    - 检验是否安装成功,在 Terminal 输入以下命令输出版本信息:arm-linux-gcc -v
    结果如图所示:得到刚刚安装的4.6.4版

    - 在 “/home/用户名” 目录下的 ".bashrc" 隐藏文件下加上和 “/etc/profile” 一样的两句

    export PATH=$PATH:/usr/local/arm/gcc-4.6.4/bin
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/arm/gcc-4.6.4/lib
    

    使用ls -a查看隐藏文件


    参考网址:https://www.cnblogs.com/tansuoxinweilai/p/11602830.html

  • 相关阅读:
    (OK) port_lighttpd_to_Android——没有基于android 4.4源码
    Linux添加头文件路径—INCLUDE_PATH
    (OK) 交叉编译hello.c for android (--sysroot),不使用Android.mk和ndk-build
    Building and running Node.js for Android
    编译node-v4.2.1,出现错误:undefined reference to getpwuid_r
    我为什么向后端工程师推荐Node.js
    (OK) 编译 pcre-8.37 静态库
    port_lighttpd_to_Android——基于android 4.4源码
    深受C/C++程序员欢迎的11款IDE
    推荐!国外程序员整理的 PHP 资源大全
  • 原文地址:https://www.cnblogs.com/tzy20191327/p/15635846.html
Copyright © 2011-2022 走看看