实验封面

一、实验内容

1.阅读理解源码

进入07_httpd所在的目录,使用vi编辑器理解源代码。

2.编译应用程序

使用gcc编译器,分别对文件夹下的copy.c和httpd.c进行编译,出现copy和httpd的可执行文件。

3.下载调试

使用NFS服务方式将HPPTD下载到开发板上,并拷贝测试用的网页进行调试

4.本机测试

在台式机的浏览器中输入http://192.168.0.121,观察在客户机的浏览器中的链接请求结果和在开发板服务器上的打印信息。

二、实验代码理解

httpd.c代码分析

/ * httpd.c:  A very simple http server

* Copyfight (C) 2003  Zou jian guo

* Copyright (C) 2000 Lineo, Inc.  (www.lineo.com)

* Copyright (c) 1997-1999 D. Jeff Dionne

* Copyright (c) 1998  Kenneth Albanowski

* Copyright (c) 1999  Nick Brok

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License as published by

* the Free Software Foundation; either version 2 of the License, or

* (at your option) any later version.

*

*/

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#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)   //发送HTTP协议数据头

{

alarm(TIMEOUT);

fprintf(f,"HTTP/1.0 200 OKn"); //服务器回应http协议数据头的状态行;发送请求成功;

switch (content_type)

{

case 't':

fprintf(f,"Content-type: text/plainn"); //发送纯文本文件信息;

break;

case 'g':

fprintf(f,"Content-type: image/gifn"); //发送gif格式图片信息;

break;

case 'j':

fprintf(f,"Content-type: image/jpegn"); //发送gpeg格式图片信息;

break;

case 'h':

fprintf(f,"Content-type: text/htmln"); //发送html信息;

break;

}

fprintf(f,"Server: uClinux-httpd 0.2.2n"); //发送服务器版本信息;

fprintf(f,"Expires: 0n"); //发送文件永不过期信息;

fprintf(f,"n"); //打印换行符;

alarm(0);

return(0);

}

int DoJpeg(FILE *f, char *name)  //对jpeg格式的文件进行处理;

{

char *buf;

FILE * infile;

int count;

if (!(infile = fopen(name, "r"))) { //通过文件名打开一个文件,只读属性;

alarm(TIMEOUT);

fprintf(stderr, "Unable to open JPEG file %s, %dn", name, errno);

fflush(f);

alarm(0);

return -1;

}

PrintHeader(f,'j');//发送j类型的http协议数据头信息;

copy(infile,f); /* prints the page */

alarm(TIMEOUT);

fclose(infile);

alarm(0);

return 0;

}

int DoGif(FILE *f, char *name)  //对gif格式的文件进行处理;

{

char *buf;

FILE * infile;

int count;

if (!(infile = fopen(name, "r"))) { //通过文件名打开一个文件,只读属性;

alarm(TIMEOUT);

fprintf(stderr, "Unable to open GIF file %s, %dn", name, errno);

fflush(f);

alarm(0);

return -1;

}

PrintHeader(f,'g'); //发送g类型的http协议数据头信息

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; //dirent不仅仅指向目录,还指向目录中的具体文件,dirent结构体存储的关于文件的信息很少,所以dirent起着一个索引的作用

if ((dir = opendir(name))== 0) { //打开一个目录;

fprintf(stderr, "Unable to open directory %s, %dn", name, errno);

fflush(f);

return -1;

}

PrintHeader(f,'h'); //发送h类型的http协议数据头信息

alarm(TIMEOUT);

fprintf(f, "

Index of %s

nn",name);

alarm(0);

if (name[strlen(name)-1] != '/') { //若名字的后面没有/则默认加上 /;

strcat(name, "/");

}

while(dirent = readdir(dir)) { //读取目录;

alarm(TIMEOUT);

fprintf(f, "

%s

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, %dn", name, errno); //打印打开文件失败信息;

fflush(f);

alarm(0);

return -1;

}

PrintHeader(f,'h'); //发送http协议数据报;f表示客户连接的文件流指针用于写入http协议数据头信息;

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, %dn", name, errno);

fflush(f);

alarm(0);

return -1;

}

PrintHeader(f,'t'); //发送t类型的http协议数据头信息;

copy(infile,f); /* prints the page */

alarm(TIMEOUT);

fclose(infile);

alarm(0);

return 0;

}

int ParseReq(FILE *f, char *r)

{

char *bp; //定义指针bp;

struct stat stbuf;

char * arg; //参数指针;

char * c;

int e;

int raw;

#ifdef DEBUG

printf("req is '%s'n", r); //打印请求命令;例如:GET /img/baidu_sylogo1.gif HTTP/1.1rn

#endif

while(*(++r) != ' ');  /*skip non-white space*/ //判断buf中的内容是否为空跳过非空白;

while(isspace(*r))   //判断r所在位置的字符是否为空格若为空格则r指向下一个字符;

r++;

while (*r == '/')  //判断r所在位置的字符是否为/若为空格则r指向下一个字符;

r++;

bp = r; //将r所指向的内容赋值给bp bp指向/之后的内容;img/baidu_sylogo1.gif HTTP/1.1rn

while(*r && (*(r) != ' ') && (*(r) != '?'))

r++;//当r不为空,并求 r不为?时r指向下一个字符

#ifdef DEBUG

printf("bp='%s' %x, r='%s' n", bp, *bp,r); //打印 r和bp的值;

#endif

if (*r == '?')   //判断 r是否为 ?若为?则执行以下语句;

{

char * e; //定义指针变量;

*r = 0;  //将r所在位置处的字符设为; 的ASCII码值是0

arg = r+1; //arg指向下一个参数;

if (e = strchr(arg,' '))

{

*e = '';  //如果arg为空则将arg所在位置置为复制给e;

}

} else

{ // 如果当前r指向字符不为 '?', 将r指向字符置为 '',

arg = 0;

*r = 0;   // r处设为;

}

c = bp;//将bp赋值给c;

/*zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz*/

if (c[0] == 0x20){ //判断c中的字符内容是否为空格;若为空格

c[0]='.'; //将.和放入c数组中;

c[1]='';

}

/*zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz*/

if(c[0] == '') strcat(c,"."); //若 c中为则将.链接在c后;

if (c && !stat(c, &stbuf))  //通过文件名c获取文件信息,并保存在stbuf中

//返回值:  执行成功则返回0,失败返回-1,错误代码存于errno

{

if (S_ISDIR(stbuf.st_mode))//判断结果是否为特定的值

{

char * end = c + strlen(c); //end指向c的末尾;

strcat(c, "/index.html"); //将/index.html加到c后,后面追加;

if (!stat(c, &stbuf)) //通过文件名c获取文件信息,并保存在stbuf中 ;成功返回0;

{

DoHTML(f, c); //对html文件进行处理;

}

else

{

*end = ''; //将end指向;

DoDir(f,c); //若c中没有"/index.html" 则跳到目录处理目录代码处去执行;

}

}

else if (!strcmp(r - 4, ".gif")) //判断r中的后四个字符,即判断文件类型;

DoGif(f,c);  //若是 gif格式的文件则跳转到DoGif对其进行处理;

else if (!strcmp(r - 4, ".jpg") || !strcmp(r - 5, ".jpeg"))

DoJpeg(f,c); //若是 jpg或jpeg格式的文件则跳转到DoJpeg对其进行处理;

else if (!strcmp(r - 4, ".htm") || !strcmp(r - 5, ".html"))

DoHTML(f,c); //若是 htm格式的文件则跳转到DoHTML处对其进行处理;

else

DoText(f,c);//若是 纯文本格式的文件则跳转到DoText对其进行处理

}

else{

PrintHeader(f,'h'); //发送h类型的http协议数据头

alarm(TIMEOUT);

fprintf(f, "

404 File Not Foundn"); //打印出错信息

fprintf(f, "

The requested URL was not found on this servern");

alarm(0);

}

return 0;

}

void sigalrm(int signo) //定时器终止时发送给进程的信号;

{

/* got an alarm, exit & recycle */

exit(0);

}

int HandleConnect(int fd)

{

FILE *f;//定义文件流FILE结构体指针用来表示与客户连接的文件流指针;

char buf[160];  //定义缓冲区buf用来存放客户端的请求命令;

char buf1[160]; //定义缓冲区buf用来存放客户端的各字段信息;

f = fdopen(fd,"a+"); //以文件描述符的形式打开文件; a+ 以附加方式打开可读写的文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾后,即文件原先的内容会被保留。

if (!f) {//若文件打开失败则打印出错信息;

fprintf(stderr, "httpd: Unable to open httpd input fd, error %dn", errno);

alarm(TIMEOUT); // 闹钟函数成功则返回上一个闹钟时间的剩余时间,否则返回0。 出错返回-1

close(fd);//关闭文件描述符;

alarm(0); //将闹钟时间清0;

return 0;

}

setbuf(f, 0); //将关闭缓冲区;

alarm(TIMEOUT); //启用闹钟;

if (!fgets(buf, 150, f)) {   //直接通过f读取150个字符放入以buf为起始地址中,不成功时返回0则打印出错信息;否则fgets成功返回函数指针打印buf的内容;

fprintf(stderr, "httpd: Error reading connection, error %dn", errno);

fclose(f); //关闭文件描述符;

alarm(0);

return 0;

}

#ifdef DEBUG

printf("buf = '%s'n", buf); //打印客户机发出的请求命令;

#endif

alarm(0);  //将闹钟时间清0;

referrer[0] = '';//初始化referrer数组;

content_length = -1;  //将信息长度初始化为-1;

alarm(TIMEOUT);  //设置定时器;

//read other line to parse Rrferrer and content_length infomation

while (fgets(buf1, 150, f) && (strlen(buf1) > 2)) {  //直接通过f读取150个字符放入以buf1为起始地址的空间中;

alarm(TIMEOUT);

#ifdef DEBUG

printf("Got buf1 '%s'n", buf1); //打印buf1中的信息;

#endif

if (!strncasecmp(buf1, "Referer:", 8)) {  //将buf1中的前八个字符与字符串Referer:若相等则将将指针指向buf1中的Referer:之后;

char * c = buf1+8;

while (isspace(*c)) //判断c处是否为空格若为空格则c指向下一个字符;

c++;

strcpy(referrer, c); //将c所指的内存单元的内容复制到referrer数组中;

}

else if (!strncasecmp(buf1, "Referrer:", 9)) { //将buf1中的前九个字符与字符串Referrer:若相等则将将指针指向buf1中的Referrer:之后;

char * c = buf1+8;

char * c = buf1+9;

while (isspace(*c))  //判断c处是否为空格若为空格则c指向下一个字符;

c++;

strcpy(referrer, c); //将c所指的内存单元的内容复制到referrer数组中;

}

else if (!strncasecmp(buf1, "Content-length:", 15)) { )) { //将buf1中的前15个字符与字符串Content-length:若相等则将将指针指向buf1中的Content-length:之后;

content_length = atoi(buf1+15); //atoi类型转换将buf1中的内容转换为整型赋值给content_length;

}

}

alarm(0);

if (ferror(f)) {  //错误信息输出;

fprintf(stderr, "http: Error continuing reading connection, error %dn", 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); //若输入q则退出程序;

break;

}

}

}

int main(int argc, char *argv[])

{

int fd, s;   //定义套接字文件描述符作为客户机和服务器之间的通道;

int len;

volatile int true = 1;  //定义volatile类型的变量用来作为指向缓冲区的指针变量;

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(HTTPD_DOCUMENT_ROOT);  //改变根目录;在makefile文件中指定;

printf("starting httpd...n"); //打印启用服务器程序信息;

printf("press q to quit.n");

//  chdir("/");

if (argc > 1 && !strcmp(argv[1], "-i")) {// 若argv【1】等于-i strcmp返回0 并且 argc大于1  执行if下的语句快即关闭文件描述符;

/* I'm running from inetd, handle the request on stdin */

fclose(stderr);

HandleConnect(0); //向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,  //此函数用于设置套接口,若成功返回0,否则返回错误

sizeof(true))) == -1) {

perror("setsockopt failed");   //输出错误信息;

exit(1);

}

server_sockaddr.sin_family = AF_INET; //设置ip地址类型;

server_sockaddr.sin_port = htons(SERVER_PORT);  //设置网络端口;

server_sockaddr.sin_addr.s_addr = htonl(INADDR_ANY); //INADDR_ANY表示本地任意ip;

if(bind(s, (struct sockaddr *)&server_sockaddr,  //将所监听的端口号与服务器的地址、端口绑定;

sizeof(server_sockaddr)) == -1)  {

perror("Unable to bind socket");//若绑定失败则打印出错信息;

exit(1);

}

if(listen(s, 8*3) == -1) { //listen()声明服务器处于监听状态,并且最多允许有24个客户端处于连接待状态;

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);//ec结构体变量的长度;

if((fd = accept(s, (void *)&ec, &len)) == -1) { //接受客户机的请求,与客户机建立链接;

exit(5);

close(s);

}

HandleConnect(fd); //处理链接函数调用fd 为客户连接文件描述符;;

}

pthread_join(th_key, &retval); //以阻塞的方式等待thread指定的线程结束。当函数返回时,被等待线程的资源被收回。如果进程已经结束,那么该函数会立即返回。成功返回0;该语句不会执行到;

}

三、遇到问题及解决

1.虽然将07_httpd文件中全部拷贝进了bc中,文件夹中拥有Makefile文件,但是还是无法通过make得到该文件夹中copy和httpd的可执行文件。

解决:第一次是觉得Makefile文件中的PATH路径不对,将其改成了/home/bc/07_httpd存盘退出后发现还是无法执行,第二次我们直接使用gcc对其单步进行编译:

armv4l-unknow-linux-gcc –E copy.c –o copy.i

armv4l-unknow-linux-gcc –S copy.i –o copy.s

armv4l-unknow-linux-gcc –c copy.s –o copy.o

对于httpd的编译方式同上。

Make——工程管理器,为了减少重复工作量,“自动编译管理器”,“自动”在于它能根据文件时间戳自动发现更新过的文件而减少编译工作量,同时它通过读入makefile文件的内容来执行大量的编译工作。用户只需要编写一次简答的编译语句就可以了,也就是说以后只要敲入make即可编译全部文件,它大大提高了实际项目的工作效率,几乎所有linux下的项目编程都需要用到它。

四、实验总结

这次实验是简单嵌入式WEB服务器实验,通过实验操作,以及之前我们队copy和httpd代码的预习,让我们对于在ARM开发板上开发一个简单的WEB的过程,以及在ARM开发板上SOCKET网络编程和Linux下signal()函数的使用有了一定的了解。

从实验中更深入的了解了一些linux系统的特色、与其它系统有别的东西,我们受益匪浅,相信对于信息安全系统设计基础这门课程也有很大的帮助,我们会继续努力!

嵌入式java闹钟 实验报告_《Java程序设计》第五次实验实验报告相关推荐

  1. java教师薪资系统_“java实验代码即UML类图”之“教师工资发放”

    实验二 2. 编写程序,实现计信学院学期末教师的奖金发放.教师有属性:编号.姓名,教学总工作量,奖金:其中奖金的计算方法为: x*30 (当职称为教授时) y= x*25 (当职称为副教授时) x*2 ...

  2. java 基础面试 英文_[Java面试] 面试java基础总结大全

    原标题:[Java面试] 面试java基础总结大全 基础知识: 1.JVM.JRE和JDK的区别: JVM(Java Virtual Machine):java虚拟机,用于保证java的跨平台的特性. ...

  3. java 内存 开发 经验_有一到五年开发经验的JAVA程序员需要掌握的知识与技能!...

    JAVA是一种平台,也是一种程序设计语言,如何学好程序设计不仅仅适用于JAVA,对C++等其他程序设计语言也一样管用.有编程高手认为,JAVA也好C也好没什么分别,拿来就用.为什么他们能达到如此境界? ...

  4. 太原理工大学linux与python编程r实验报告_太原理工大学算法设计与分析实验报告...

    <太原理工大学算法设计与分析实验报告>由会员分享,可在线阅读,更多相关<太原理工大学算法设计与分析实验报告(12页珍藏版)>请在人人文库网上搜索. 1.本科实验报告课程名称: ...

  5. java 内存泄露 书籍_[Java教程]一次艰难的内存泄露排查,BeanUtils 的锅

    [Java教程]一次艰难的内存泄露排查,BeanUtils 的锅 0 2020-10-29 18:24:42 现象 通过jstat -gcutil pid 5000 ,发现fgc次数很多而且频繁,此时 ...

  6. java privatekey输出字符串_[Java教程]根据字符串(String)生成公钥(PublicKey)和私钥(PrivateKey)对象_星空网...

    根据字符串(String)生成公钥(PublicKey)和私钥(PrivateKey)对象 2012-05-29 0 1.字符串生成公钥对象 PublicKey /** * 实例化公钥 * * @re ...

  7. java视、频_[java视频]感人故 事视 频网 站上那找~~~

    感人故 事视 频网 站上那找~~~ 问题补充:感人故 事视 频网 站上那找~~~ ●呵呵,你问对人了,感人故事就去"新浪show",现在是新浪期下的网站,运行稳定,观看流畅,上传简 ...

  8. java 历遍 类_[Java] 遍历指定包名下所有的类(支持jar) | 学步园

    项目需要,仅做记录. 支持包名下的子包名遍历,并使用Annotation(内注)来过滤一些不必要的内部类,提高命中精度. 通过Thread.currentThread().getContextClas ...

  9. java 图片宽高_[Java]获取图片高和宽

    通过javax.imageio.ImageIO类中的read()函数读取的图片,存放在类java.awt.image.BufferedImage类中.调用BufferedImage类中的getWidt ...

  10. java语言金山打字_[Java教程]java实现 swing模仿金山打字 案例源码

    [Java教程]java实现 swing模仿金山打字 案例源码 0 2014-11-17 12:00:21 java实现 swing模仿金山打字 案例源码,更多Java技术就去Java教程网.http ...

最新文章

  1. TypeError: can only concatenate str (not “float“) to str
  2. mysql运维工资_MySQL运维踩坑
  3. mysql驱动(github上的)
  4. Elide 4.3.1 发布,雅虎开源的应用数据 API 搭建平台
  5. Solaris IPMP 配置
  6. 叉乘(三)——线段与线段相交吗?
  7. 查看mysql的版本的四种方法
  8. 【Python】选择Python2还是Python3?
  9. (7) hibernate之级联cascade和关系维持inverse
  10. Oracle数据库中闪回恢复的详细分析
  11. mysql my.cnf 配置建议
  12. 深度学习(deep learning)优化调参细节(trick)
  13. Windows7中安装内存与可用内存不一致的解决办法
  14. python实现批量下载视频_python批量下载抖音视频
  15. 软件测试工程师面试自我介绍部分模板
  16. win7无法连接打印机拒绝访问_win7系统共享打印机拒绝访问的完美解决方法
  17. 计算机软件专业河南省专科学校,计算机相关专业河南省哪个学校好
  18. python代码加密运行_python源码下载后怎样进行加密
  19. pycharm运行程序时在Python console窗口中运行
  20. 2018年8月1日每日安全快讯 | 数十万酷视网络摄像头存在高危风险,可导致视频泄露

热门文章

  1. 安装Oralce时,系统参数详解
  2. 在Android开发中怎样调用系统Email发送邮件
  3. docker安装nginx实例
  4. php文章付费阅读系统球料付费阅读系统
  5. Android多线程断点下载
  6. java软件设计模式只单例设计模式
  7. Log4j源代码学习
  8. C# MySQL数据库的备份 还原 初始化
  9. grails的controller和action那点事---远程调试groovy代码
  10. HDU 1080 Human Gene Functions