首页 > 代码库 > 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)