博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Socket网络编程--简单Web服务器(3)
阅读量:5979 次
发布时间:2019-06-20

本文共 5287 字,大约阅读时间需要 17 分钟。

  上一小节已经实现了浏览器发送请求,然后服务器给出应答信息,然后浏览器显示出服务器发送过来的网页。一切看起来都是那么的美好。这一小节就准备实现可以根据地址栏url的不同来返回指定的网页。目前还不考虑带参数的问题。

  stat函数

#include <sys/stat.h>

int stat(const char *restrict pathname,struct stat * restrict buf);

int fstat(int filedes,struct stat * buf);

int lstat(const char *restrict pathname,struct stat * restrict buf);

给出pathname,stat函数就返回与此命名文件有关的信息结构。fstat函数获取已在描述符filedes上打开文件的有关信息。lstat函数类似与stat,但是命名的文件不是个符号链接。

  实现指定url访问指定目录的web服务器

1 int WebServer::ServerRequest(int cli_fd) 2 { 3     char buf[1024]; 4     int size=1024; 5     int i,j; 6     char method[255];//用于保存请求方式 7     char url[512]; 8     char path[1024]; 9     struct stat st;10     int cgi;11     memset(buf,0,sizeof(buf));12     cgi=0;13     //获取第一行请求信息 一般格式为: GET / HTTP/1.114     //                               POST / HTTP/1.115     size=get_line(cli_fd,buf,sizeof(buf));16     cout<<"\t\t"<
<
0) && strcmp("\n",buf))//去除掉多余的请求头信息61 size=get_line(cli_fd,buf,sizeof(buf));62 Page_404(cli_fd);63 }64 else65 {66 if((st.st_mode & S_IFMT)== S_IFDIR)//判断url地址,如果是个目录,那么就访问该目录的index.html67 {68 strcat(path,"/index.html");69 }70 if((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH))//判断该url地址所对应的文件是否是可执行,并且是否有权限71 {72 cgi=1;//是一个cgi程序73 }74 if(cgi==0)//如果cgi为0,那么就表示该url所对应的文件不是cgi程序,而是一个简单的静态页面75 {76 ServerCatHttpPage(cli_fd,path);77 }78 }79 80 if(fork()==0)81 {82 //处理阶段83 //execl("/bin/ls","ls","/home/myuser/",NULL);84 //Page_200(cli_fd);85 }86 close(cli_fd);87 return 0;88 }

  返回页的代码

1 int WebServer::ServerCatHttpPage(int cli_fd,char *path) 2 { 3     FILE * resource=NULL; 4     int size=1; 5     char buf[1024]; 6     buf[0]=1;buf[1]=0; 7     while((size>0) && strcmp("\n",buf))//去除掉多余的请求头信息 8         size=get_line(cli_fd,buf,sizeof(buf)); 9 10     resource=fopen(path,"r");//根据GET后面的文件吗,将文件打开11     if(resource==NULL)//打开文件失败12     {13         Page_404(cli_fd);14     }15     else16     {17         char type[32]="text/html";18         char * p =type;19         Page_Headers(cli_fd,p);20         Page_Cat(cli_fd,resource);21     }22     fclose(resource);23     return 0;24 }
1 int WebServer::Page_Headers(int cli_fd,char * type) 2 { 3     char buf[1024]; 4     strcpy(buf,"HTTP/1.1 200 OK\r\n"); 5     send(cli_fd, buf, strlen(buf), 0); 6     sprintf(buf, "Server:wunaozai.cnblogs.com\r\n"); 7     send(cli_fd, buf, strlen(buf), 0); 8     sprintf(buf, "Content-Type: %s\r\n",type); 9     send(cli_fd, buf, strlen(buf), 0);10     sprintf(buf, "\r\n");11     send(cli_fd, buf, strlen(buf), 0);12     return 0;13 }14 int WebServer::Page_Cat(int cli_fd,FILE * fp)15 {16     char buf[1024];17 18     fgets(buf,sizeof(buf),fp);19     while(!feof(fp))20     {21         send(cli_fd,buf,strlen(buf),0);22         fgets(buf,sizeof(buf),fp);23     }24     return 0;25 }

  代码写好了,我在当前目录下创建一个www的目录在里面有个index.html和text.html的页面。然后我们通过浏览器进行返回。得到的结果如下:

  可以看出都显示了指定的网页信息,而最后一个是404页面,可是为什么会有乱码呢,应该是在应答信息哪里没有指点编码格式。所以我们在Page_404这个函数里的Content-Type这一行进行如下修改

1 sprintf(buf, "Content-Type: text/html;charset=utf-8\r\n");

  当然还可以在html网页上进行指定。

  本小结篇幅比较少,接下来就实现传输一个ico图标吧。我们都知道一个html网页是通过一个url进行查找文件然后以http协议发送个浏览器。但是我们服务器怎么发送css或js或图片给浏览器呢?怎么知道那些是要的那些是不要的。一看是还以为很难,上网查了一下,原来很简单的。浏览器接收到根据url发送过来的html文件,然后浏览器会分析这个html文件中代码的图片文件,css文件等,然后在跟服务器建立一个http请求,请求一个新的文件。在发送的过程中,不是直接发送图片过去的,而是先编织成HTTP的格式发送给浏览器,其中还要指定这个图片的格式,大概就是这样了。说起来比较抽象,我用wireshark抓一个包看看。

   可以看出这个应答信息的格式跟以前讲的是一样的。也是一个应答头,然后在应答头里有个Content-Length属性,里面包含接下来要接收的文件大小。

  一开始使用下面代码进行文件的读取

1 int WebServer::Page_Cat(int cli_fd,FILE * fp) 2 { 3     char buf[1024]; 4  5     fgets(buf,sizeof(buf),fp); 6     while(!feof(fp)) 7     { 8         send(cli_fd,buf,strlen(buf),0); 9         fgets(buf,sizeof(buf),fp);10     }11     return 0;12 }

  然后在浏览器进行访问,然后就是一直访问不到图片资源,一直弄到凌晨几点。今天,想了个办法,对于图片一个字节一个字节的打印出来,弄了好久才知道,原来是因为图片资源里面有ascii码为0的字符,所以导致在发送的时候使用strlen时发送数据会不完整。哎......这个以后要注意啊。所以我准备使用fgetc来获取数据,要注意fgetc的返回值是int型,用char会出错,应该没有人跟我一样不小心吧。

1 int WebServer::Page_Headers(int cli_fd,char * type,int filesize) 2 { 3     char buf[1024]; 4     strcpy(buf,"HTTP/1.1 200 OK\r\n"); 5     send(cli_fd, buf, strlen(buf), 0); 6     sprintf(buf, "Server:wunaozai.cnblogs.com\r\n"); 7     send(cli_fd, buf, strlen(buf), 0); 8     sprintf(buf, "Content-Type: %s\r\n",type); 9     send(cli_fd, buf, strlen(buf), 0);10     sprintf(buf, "Content-Length: %d\r\n",filesize);11     send(cli_fd, buf, strlen(buf), 0);12     sprintf(buf, "\r\n");13     send(cli_fd, buf, strlen(buf), 0);14     return 0;15 }16 int WebServer::Page_Cat(int cli_fd,FILE * fp)17 {18     int c;19 20     while((c=fgetc(fp))!=EOF)21     {22         send(cli_fd,&c,1,0);23     }24     return 0;25 }

  ServerCatHttpPage函数的代码如下

1 int WebServer::ServerCatHttpPage(int cli_fd,char *path,int filesize) 2 { 3     FILE * resource=NULL; 4     int size=1; 5     char buf[1024]; 6     char type[32]; 7     char * p =type; 8     buf[0]=1;buf[1]=0; 9     while((size>0) && strcmp("\n",buf))//去除掉多余的请求头信息10         size=get_line(cli_fd,buf,sizeof(buf));11 12     //判断文件类型13     int len=strlen(path);14     cout<
<<":"<
<

   好了,感觉还不错的样子。

 

  参考资料: 

        

  本文地址: 

转载地址:http://ueaox.baihongyu.com/

你可能感兴趣的文章
软件测试 -- 和用户共同测试(UAT测试)的注意点有哪些
查看>>
Docker的基本使用
查看>>
[NHibernate]ISessionFactory配置
查看>>
[C#]二维码(QR Code)生成与解析
查看>>
[Node.js]OS模块
查看>>
python全栈开发笔记----基本数据类型---列表方法
查看>>
FastReport快速安装教程
查看>>
wordCount总结
查看>>
栈的应用 表达式求值
查看>>
预防U盘被病毒侵害的方法
查看>>
[Java]Thinking in Java 练习2.12
查看>>
SpringMVC原理+流程图
查看>>
SQL Server实现跨库查询(跨库select insert)
查看>>
Android Studio 修改注释模板中的${USER}变量(转)
查看>>
HDOJ_ACM_Super Jumping! Jumping! Jumping!
查看>>
左神算法基础班4_1&2实现二叉树的先序、中序、后序遍历,包括递归方式和非递归...
查看>>
xe6 android控件透明度设置方法
查看>>
linux signal
查看>>
关于PHP SESSION
查看>>
leetcode 20. Valid Parentheses
查看>>