Socket网络编程--简单Web服务器(4)
上一小节已经实现了对图片的传输,接下来就是判断文件是否为js,css,png等格式。我们增加一个函数用于判断格式
int WebServer::get_filetype(char *type,char *path)//用于判断该url指向文件的后缀
{
if(strstr(path,".html"))
strcpy(type,"text/html");
else if(strstr(path,".gif"))
strcpy(type,"image/gif");
else if(strstr(path,".jpg"))
strcpy(type,"image/jpeg");
else if(strstr(path,".png"))
strcpy(type,"image/png");
else if(strstr(path,".ico"))
strcpy(type,"image/x-icon");
else if(strstr(path,".js"))
strcpy(type,"text/javascript");
else if(strstr(path,".json"))
strcpy(type,"application/json");
else if(strstr(path,".css"))
strcpy(type,"text/css");
else
strcpy(type,"text/plain");
return ;
}
然后修改一下主页index.html的文件
<html>
<head>
<title>Test</title>
<meta http-equiv="Content-Type" content="text/html ; charset=utf-8">
<link rel="stylesheet" href="style.css" type="text/css"/>
<script language="javascript" src="javascript.js"></script>
</head> <body>
<div class="ceshi">图片</div><img src="ab.jpg"></img>
<input name="button" type="button" value="Click!" onclick=hi();></input>
</body>
</html>
两个外部文件如下
[myuser@bogon www]$ cat style.css
.ceshi {font-size:20px; color:#ff0000;}
[myuser@bogon www]$ cat javascript.js
function hi()
{
alert("js 调用,你单机了按钮");
}
[myuser@bogon www]$
下面这个是运行的结果图

用chrome浏览器的F12调试工具获取到的状态,可以看到,该网页可以获取到index.html,然后浏览器会根据这个页面再发送index.html文件所需要的外部文件的请求,从上面可以看出请求了style.css,javascript.js和ab.jpg图片。然后显示网页,我单击了那个button也是可以调用js脚本的。
接下来就是判断一个提交是get还是post,网页index.html的源代码
<body>
<div class="ceshi">图片</div><img src="ab.jpg"></img>
<input name="button" type="button" value="Click!" onclick=hi();></input> <hr>
<br>使用post方式<br>
<form method="post" name="frm1">
<label>用户名:</label>
<input type="text" name="username" />
<br>
<label>密码:</label>
<input type="password" name="password" />
<br>
<input type="submit" name="commit" value="登陆"/>
<br>
</form>
<hr>
<br>使用get方式<br>
<form method="get" name="frm1" action="index.html">
<label>用户名:</label>
<input type="text" name="username" />
<br>
<label>密码:</label>
<input type="password" name="password" />
<br>
<input type="submit" name="commit" value="登陆"/>
<br>
</form>
</body>
修改后的ServerRequest函数
int WebServer::ServerRequest(int cli_fd)
{
char buf[];
int size=;
int i,j;
char method[];//用于保存请求方式
char url[];
char path[];
char args[];
struct stat st;
int cgi;//cgi 为0 表示get普通方法 1表示get带参方法 2表示post方法
pid_t pid;
memset(buf,,sizeof(buf));
cgi=;
//获取第一行请求信息 一般格式为: GET / HTTP/1.1
// POST / HTTP/1.1
size=get_line(cli_fd,buf,sizeof(buf));
//cout<<"\t\t"<<buf<<endl;
i=,j=;
//截取第一个单词
while(!isspace(buf[j]) && (i<sizeof(method)-))
{
method[i]=buf[j];
i++;j++;
}
method[i]='\0';
//取第一个与第二个单词之间的空格
while(isspace(buf[j]) && (j<sizeof(buf)))
j++; if(strcasecmp(method,"GET") && strcasecmp(method,"POST"))
{
Page_501(cli_fd);
return -;
} if(strcasecmp(method,"GET")==)
{
cout<<"此次请求的方式是GET方法"<<endl;
cgi=;
}
else if(strcasecmp(method,"POST")==)
{
cout<<"此次请求的方式是POST方法"<<endl;
cgi=;
} //截取第二个单词
i=;
int flag=;
while(!isspace(buf[j]) && (i<sizeof(url)-) && (j<sizeof(buf)))
{
if(buf[j]=='?')
{
flag=;
j++;
i=;
url[i]='\0';
cgi=(cgi==?:);
continue;
}
if(flag==)
{
url[i]=buf[j];
i++;j++;
}
else if(flag==)
{
args[i]=buf[j];
i++;j++;
}
}
if(flag==)
url[i]='\0';
else
args[i]='\0'; sprintf(path,"www%s",url);//这个是web服务器的主目录,这个以后可以处理成读取配置文件,这里就先写固定的www目录
if(path[strlen(path)-]=='/')
strcat(path,"index.html");//同上 //cout<<"============>此次请求的地址为:"<<path<<":"<<args<<endl; //根据文件名,获取该文件的文件信息。如果为-1,表示获取该文件失败
if(stat(path,&st)==-)
{
while((size>) && strcmp("\n",buf))//去除掉多余的请求头信息
size=get_line(cli_fd,buf,sizeof(buf));
Page_404(cli_fd);
}
else
{
if(S_ISDIR(st.st_mode))//判断url地址,如果是个目录,那么就访问该目录的index.html
{
strcat(path,"/index.html");
//cout<<"此次请求的地址为:"<<path<<endl;
}
if(!S_ISDIR(st.st_mode)&&((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH)))//判断该url地址所对应的文件是否是可执行,并且是否有权限
{
cgi=;//是一个cgi程序
}
if(cgi==)//如果cgi为0,那么就表示该url所对应的文件不是cgi程序,而是一个简单的静态页面
{
pid = fork();
if(pid==)
{
ServerCatHttpPage(cli_fd,path,st.st_size);
}
}
else if(cgi==)//get方法带参数
{
pid=fork();
if(pid==)
{
while((size>) && strcmp("\n",buf))//去除掉多余的请求头信息
size=get_line(cli_fd,buf,sizeof(buf));
ServerGetFunction(cli_fd,path,args);
}
}
else if(cgi==)//post方法
{
pid=fork();
if(pid==)
{
int content_length=;
while((size>) && strcmp("\n",buf))//去除掉多余的请求头信息
{
size=get_line(cli_fd,buf,sizeof(buf));
buf[]='\0';
if(strcasecmp(buf,"Content-Length:")==)
{
content_length=atoi(&(buf[]));
}
}
if(content_length==)
{
Page_400(cli_fd);
return ;
}
char c;
j=;
for(int i=;i<content_length;i++)
{
recv(cli_fd,&c,,);
args[j]=c;
j++;
}
args[j]=;
ServerPostFunction(cli_fd,path,args);
}
}
}
close(cli_fd);
return ;
}
增加的两个处理cgi程序的函数(下小节实现)
int WebServer::ServerGetFunction(int cli_fd,char *path,char *args)
{
cout<<"cli_fd:"<<cli_fd<<" path:"<<path<<" args:"<<args<<endl;
Page_200(cli_fd);
return ;
}
int WebServer::ServerPostFunction(int cli_fd,char *path,char *args)
{
cout<<"cli_fd:"<<cli_fd<<" path:"<<path<<" args:"<<args<<endl;
Page_200(cli_fd);
return ;
}
下面这个是运行的结果

从上图可以看出通过GET方法和POST方法都可以正常的获取到从表单那里传过去的参数。我们知道中文在url地址中的显示是显示成16进制的。这个是URL编码。接下来要实现对这个URL编码进行转换,这里使用网上别人提供的代码。
#include <ctype.h>
#include <string>
#include <string.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;
static int php_htoi(char *s)
{
int value;
int c; c = ((unsigned char *)s)[];
if (isupper(c))
c = tolower(c);
value = (c >= '' && c <= '' ? c - '' : c - 'a' + ) * ; c = ((unsigned char *)s)[];
if (isupper(c))
c = tolower(c);
value += c >= '' && c <= '' ? c - '' : c - 'a' + ; return (value);
}
/*
*URL解码,提取自PHP 5.2.17
*用法:string urldecode(string str_source)
*时间:2012-8-14 By Dewei
* */
string urldecode(string &str_source)
{
char const *in_str = str_source.c_str();
int in_str_len = strlen(in_str);
int out_str_len = ;
string out_str;
char *str; str = strdup(in_str);
char *dest = str;
char *data = str; while (in_str_len--) {
if (*data == '+') {
*dest = ' ';
}
else if (*data == '%' && in_str_len >= && isxdigit((int) *(data + ))
&& isxdigit((int) *(data + ))) {
*dest = (char) php_htoi(data + );
data += ;
in_str_len -= ;
} else {
*dest = *data;
}
data++;
dest++;
}
*dest = '\0';
out_str_len = dest - str;
out_str = str;
free(str);
return out_str;
} int main()
{
string str="username=%E7%99%BB%E5%BD%95";
string out=urldecode(str);
cout<<out<<endl;
return ;
}
我们通过在传参的时候调用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)的更多相关文章
- Socket网络编程--简单Web服务器(6)
本来是想实现ssl连接的,但是弄了好久都不成功,就索性不做了,等以后有能力再做了.所以这一小节就是本次的最后一节了.就简单的说几个注意点. 1.加个配置文件 使用单例模式,使用一个类,该类保存一些信息 ...
- Socket网络编程--简单Web服务器(1)
这一次的Socket系列准备讲Web服务器.就是编写一个简单的Web服务器,具体怎么做呢?我也不是很清楚流程,所以我找来了一个开源的小的Web服务器--tinyhttpd.这个服务器才500多行的代码 ...
- Socket网络编程--简单Web服务器(2)
上一小节通过阅读开源的Web服务器--tinyhttpd.大概知道了一次交互的请求信息和应答信息的具体过程.接下来我就自己简单的实现一个Web服务器. 下面这个程序只是实现一个简单的框架出来.这次先实 ...
- Socket网络编程--简单Web服务器(3)
上一小节已经实现了浏览器发送请求,然后服务器给出应答信息,然后浏览器显示出服务器发送过来的网页.一切看起来都是那么的美好.这一小节就准备实现可以根据地址栏url的不同来返回指定的网页.目前还不考虑带参 ...
- Socket网络编程--简单Web服务器(5)
这一小节我们将实现服务器对get和post的请求进行对cgi程序的调用.对于web服务器以前的章节已经实现了对get和post请求的调用接口,接下来给出对应接口的实现. int WebServer:: ...
- C++ socket 网络编程 简单聊天室
操作系统里的进程通讯方式有6种:(有名/匿名)管道.信号.消息队列.信号量.内存(最快).套接字(最常用),这里我们来介绍用socket来实现进程通讯. 1.简单实现一个单向发送与接收 这是套接字的工 ...
- C#中使用Socket实现简单Web服务器
上一篇博客中介绍了怎样使用socket访问web服务器.关键有两个: 熟悉Socket编程: 熟悉HTTP协议. 上一篇主要是通过socket来模拟浏览器向(任何)Web服务器发送(HTTP)请求,重 ...
- Java Web 基础(一) 基于TCP的Socket网络编程
一.Socket简单介绍 Socket通信作为Java网络通讯的基础内容,集中了异常.I/O流模式等众多知识点.学习Socket通信,既能够了解真正的网络通讯原理,也能够增强对I/O流模式的理解. 1 ...
- python之Socket网络编程
什么是网络? 网络是由节点和连线构成,表示诸多对象及其相互联系.在数学上,网络是一种图,一般认为专指加权图.网络除了数学定义外,还有具体的物理含义,即网络是从某种相同类型的实际问题中抽象出来的模型.在 ...
随机推荐
- 001 Python中的基本类型初步介绍
这个但是根据书来整理的,显得有些多,也不够完整. 一:介绍 1.为什么使用内置对象 对象类型是语言的一个部分 内置对象构成了每个python程序的核心部分 二:数字 1.**是乘方 2.math数学模 ...
- 073 HBASE的读写以及client API
一:读写思想 1.系统表 hbase:namespace 存储hbase中所有的namespace的信息 hbase:meta rowkey:hbase中所有表的region的名称 column:re ...
- memcahe
网站的瓶颈 主要集中在数据库 ,用缓存(直接操作内存) 存储计算机的内存,如果一旦服务器断电,数据都将清空 内存:memcached redis基于文档:mongodb memcache:基于内存的高 ...
- 004.Docker镜像管理
一 镜像基本操作 镜像是一个包含程序运行必要依赖环境和代码的只读文件,其本质是磁盘上一系列文件的集合.它采用分层的文件系统,将每一次改变以读写层的形式增加到原来的只读文件上.镜像是容器运行的基石. 1 ...
- Leetcode分类总结(Greedy)
贪心类题目目前除了正则匹配(Wildcard Matching)(据说其实是DP)那道还没做其他的免费题目都做了,简单做个总结. 贪心的奥义就是每一步都选择当前回合”可见范围“(即可得知的信息)内的最 ...
- dns安全 涉及 术语
僵木蠕 以“僵木蠕”(僵尸网络.木马.蠕虫)为代表的网络威胁 僵尸网络是攻击者出于恶意目的,传播僵尸程序bot以控制大量计算机,并通过一对多的命令与控制信道所组成的网络,我们将之称之为僵尸网络,bot ...
- Windows 7 Boot Updater 如何使用
作者:韩梦飞沙 Author:han_meng_fei_sha 邮箱:313134555@qq.com E-mail: 313134555 @qq.com 如何使用 动画如果你选择改变动画,你将不得不 ...
- [COGS2554][SYZOJ247][福利]可持久化线段树
思路: 主席树模板. 注意内存的分配,原始的线段树有$2n$个结点,每次更新时最多增加$log(n)$个结点,总共有$q$次询问,所以存储结点的数组大小为$2N+q log(n)$. #include ...
- 面向对象&网络编程
1 接口与归一化设计 1.1 归一化概念: 归一化的好处: 1.归一化让使用者无需关心对象的类是什么,只需要知道这些对象都具备某些功能就可以了,这极大降低了使用者的使用难度. 2.归一化使得高层的外部 ...
- React系列文章:无状态组件生成真实DOM结点
在上一篇文章中,我们总结并模拟了JSX生成真实DOM结点的过程,今天接着来介绍一下无状态组件的生成过程. 先以下面一段简单的代码举例: const Greeting = function ({name ...