首页 > 代码库 > Socket网络编程--简单Web服务器(4)

Socket网络编程--简单Web服务器(4)

  上一小节已经实现了对图片的传输,接下来就是判断文件是否为js,css,png等格式。我们增加一个函数用于判断格式

 1 int WebServer::get_filetype(char *type,char *path)//用于判断该url指向文件的后缀 2 { 3     if(strstr(path,".html")) 4         strcpy(type,"text/html"); 5     else if(strstr(path,".gif")) 6         strcpy(type,"image/gif"); 7     else if(strstr(path,".jpg")) 8         strcpy(type,"image/jpeg"); 9     else if(strstr(path,".png"))10         strcpy(type,"image/png");11     else if(strstr(path,".ico"))12         strcpy(type,"image/x-icon");13     else if(strstr(path,".js"))14         strcpy(type,"text/javascript");15     else if(strstr(path,".json"))16         strcpy(type,"application/json");17     else if(strstr(path,".css"))18         strcpy(type,"text/css");19     else20         strcpy(type,"text/plain");21     return 0;22 }

  然后修改一下主页index.html的文件

 1 <html> 2     <head> 3         <title>Test</title> 4         <meta http-equiv="Content-Type" content="text/html ; charset=utf-8"> 5         <link rel="stylesheet" href="style.css" type="text/css"/> 6         <script language="javascript" src="javascript.js"></script> 7     </head> 8  9     <body>10         <div class="ceshi">图片</div><img src="ab.jpg"></img>11         <input name="button" type="button" value="Click!" onclick=hi();></input>12     </body>13 </html>

  两个外部文件如下

1 [myuser@bogon www]$ cat style.css2 .ceshi {font-size:20px; color:#ff0000;}3 [myuser@bogon www]$ cat javascript.js4 function hi()5 {6     alert("js 调用,你单机了按钮");7 }8 [myuser@bogon www]$

  下面这个是运行的结果图

  用chrome浏览器的F12调试工具获取到的状态,可以看到,该网页可以获取到index.html,然后浏览器会根据这个页面再发送index.html文件所需要的外部文件的请求,从上面可以看出请求了style.css,javascript.js和ab.jpg图片。然后显示网页,我单击了那个button也是可以调用js脚本的。

  接下来就是判断一个提交是get还是post,网页index.html的源代码

 1     <body> 2         <div class="ceshi">图片</div><img src="ab.jpg"></img> 3         <input name="button" type="button" value="Click!" onclick=hi();></input> 4  5         <hr> 6         <br>使用post方式<br> 7         <form method="post" name="frm1"> 8             <label>用户名:</label> 9             <input type="text" name="username" />10             <br>11             <label>密码:</label>12             <input type="password" name="password" />13             <br>14             <input type="submit" name="commit" value="登陆"/>15             <br>16         </form>17         <hr>18         <br>使用get方式<br>19         <form method="get" name="frm1" action="index.html">20             <label>用户名:</label>21             <input type="text" name="username" />22             <br>23             <label>密码:</label>24             <input type="password" name="password" />25             <br>26             <input type="submit" name="commit" value="登陆"/>27             <br>28         </form>29     </body>

  修改后的ServerRequest函数

  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     char args[1024]; 10     struct stat st; 11     int cgi;//cgi 为0 表示get普通方法 1表示get带参方法  2表示post方法 12     pid_t pid; 13     memset(buf,0,sizeof(buf)); 14     cgi=0; 15     //获取第一行请求信息 一般格式为: GET / HTTP/1.1 16     //                               POST / HTTP/1.1 17     size=get_line(cli_fd,buf,sizeof(buf)); 18     //cout<<"\t\t"<<buf<<endl; 19     i=0,j=0; 20     //截取第一个单词 21     while(!isspace(buf[j]) && (i<sizeof(method)-1)) 22     { 23         method[i]=buf[j]; 24         i++;j++; 25     } 26     method[i]=\0; 27     //取第一个与第二个单词之间的空格 28     while(isspace(buf[j]) && (j<sizeof(buf))) 29         j++; 30  31     if(strcasecmp(method,"GET") && strcasecmp(method,"POST")) 32     { 33         Page_501(cli_fd); 34         return -1; 35     } 36  37     if(strcasecmp(method,"GET")==0) 38     { 39         cout<<"此次请求的方式是GET方法"<<endl; 40         cgi=0; 41     } 42     else if(strcasecmp(method,"POST")==0) 43     { 44         cout<<"此次请求的方式是POST方法"<<endl; 45         cgi=2; 46     } 47  48     //截取第二个单词 49     i=0; 50     int flag=0; 51     while(!isspace(buf[j]) && (i<sizeof(url)-1) && (j<sizeof(buf))) 52     { 53         if(buf[j]==?) 54         { 55             flag=1; 56             j++; 57             i=0; 58             url[i]=\0; 59             cgi=(cgi==0?1:2); 60             continue; 61         } 62         if(flag==0) 63         { 64             url[i]=buf[j]; 65             i++;j++; 66         } 67         else if(flag==1) 68         { 69             args[i]=buf[j]; 70             i++;j++; 71         } 72     } 73     if(flag==0) 74         url[i]=\0; 75     else 76         args[i]=\0; 77  78     sprintf(path,"www%s",url);//这个是web服务器的主目录,这个以后可以处理成读取配置文件,这里就先写固定的www目录 79     if(path[strlen(path)-1]==/) 80         strcat(path,"index.html");//同上 81  82     //cout<<"============>此次请求的地址为:"<<path<<":"<<args<<endl; 83  84     //根据文件名,获取该文件的文件信息。如果为-1,表示获取该文件失败 85     if(stat(path,&st)==-1) 86     { 87         while((size>0) && strcmp("\n",buf))//去除掉多余的请求头信息 88             size=get_line(cli_fd,buf,sizeof(buf)); 89         Page_404(cli_fd); 90     } 91     else 92     { 93         if(S_ISDIR(st.st_mode))//判断url地址,如果是个目录,那么就访问该目录的index.html 94         { 95             strcat(path,"/index.html"); 96             //cout<<"此次请求的地址为:"<<path<<endl; 97         } 98         if(!S_ISDIR(st.st_mode)&&((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)))//判断该url地址所对应的文件是否是可执行,并且是否有权限 99         {100             cgi=2;//是一个cgi程序101         }102         if(cgi==0)//如果cgi为0,那么就表示该url所对应的文件不是cgi程序,而是一个简单的静态页面103         {104             pid = fork();105             if(pid==0)106             {107                 ServerCatHttpPage(cli_fd,path,st.st_size);108             }109         }110         else if(cgi==1)//get方法带参数111         {112             pid=fork();113             if(pid==0)114             {115                 while((size>0) && strcmp("\n",buf))//去除掉多余的请求头信息116                     size=get_line(cli_fd,buf,sizeof(buf));117                 ServerGetFunction(cli_fd,path,args);118             }119         }120         else if(cgi==2)//post方法121         {122             pid=fork();123             if(pid==0)124             {125                 int content_length=0;126                 while((size>0) && strcmp("\n",buf))//去除掉多余的请求头信息127                 {128                     size=get_line(cli_fd,buf,sizeof(buf));129                     buf[15]=\0;130                     if(strcasecmp(buf,"Content-Length:")==0)131                     {132                         content_length=atoi(&(buf[16]));133                     }134                 }135                 if(content_length==0)136                 {137                     Page_400(cli_fd);138                     return 0;139                 }140                 char c;141                 j=0;142                 for(int i=0;i<content_length;i++)143                 {144                     recv(cli_fd,&c,1,0);145                     args[j]=c;146                     j++;147                 }148                 args[j]=0;149                 ServerPostFunction(cli_fd,path,args);150             }151         }152     }153     close(cli_fd);154     return 0;155 }

  增加的两个处理cgi程序的函数(下小节实现)

 1 int WebServer::ServerGetFunction(int cli_fd,char *path,char *args) 2 { 3     cout<<"cli_fd:"<<cli_fd<<"  path:"<<path<<"  args:"<<args<<endl; 4     Page_200(cli_fd); 5     return 0; 6 } 7 int WebServer::ServerPostFunction(int cli_fd,char *path,char *args) 8 { 9     cout<<"cli_fd:"<<cli_fd<<"  path:"<<path<<"  args:"<<args<<endl;10     Page_200(cli_fd);11     return 0;12 }

  下面这个是运行的结果

   从上图可以看出通过GET方法和POST方法都可以正常的获取到从表单那里传过去的参数。我们知道中文在url地址中的显示是显示成16进制的。这个是URL编码。接下来要实现对这个URL编码进行转换,这里使用网上别人提供的代码。

 1 #include <ctype.h> 2 #include <string> 3 #include <string.h> 4 #include <stdio.h> 5 #include <iostream> 6 #include <stdlib.h> 7 using namespace std; 8 static int php_htoi(char *s) 9 {10     int value;11     int c;12 13     c = ((unsigned char *)s)[0];14     if (isupper(c))15         c = tolower(c);16     value = http://www.mamicode.com/(c >= 0 && c <= 9 ? c - 0 : c - a + 10) * 16;17 18     c = ((unsigned char *)s)[1];19     if (isupper(c))20         c = tolower(c);21     value += c >= 0 && c <= 9 ? c - 0 : c - a + 10;22 23     return (value);24 }25 /*26  *URL解码,提取自PHP 5.2.1727  *用法:string urldecode(string str_source)28  *时间:2012-8-14 By Dewei29  * */30 string urldecode(string &str_source)31 {32     char const *in_str = str_source.c_str();33     int in_str_len = strlen(in_str);34     int out_str_len = 0;35     string out_str;36     char *str;37 38     str = strdup(in_str);39     char *dest = str;40     char *data =http://www.mamicode.com/ str;41 42     while (in_str_len--) {43         if (*data =http://www.mamicode.com/= +) {44             *dest =  ;45         }46         else if (*data =http://www.mamicode.com/= % && in_str_len >= 2 && isxdigit((int) *(data + 1))47                 && isxdigit((int) *(data + 2))) {48             *dest = (char) php_htoi(data + 1);49             data += 2;50             in_str_len -= 2;51         } else {52             *dest = *data;53         }54         data++;55         dest++;56     }57     *dest = \0;58     out_str_len =  dest - str;59     out_str = str;60     free(str);61     return out_str;62 }63 64 int main()65 {66     string str="username=%E7%99%BB%E5%BD%95";67     string out=urldecode(str);68     cout<<out<<endl;69     return 0;70 }

  我们通过在传参的时候调用urldecode进行解码就可以实现中文显示了。

  这一节就到这里,下一小节将实现对cgi的支持。 

 

  参考资料: http://blog.csdn.net/xiaojianpitt/article/details/4389247

      : http://dewei.iteye.com/blog/1630969 (关于URL编码解码代码)

  本文地址: http://www.cnblogs.com/wunaozai/p/3945218.html

Socket网络编程--简单Web服务器(4)