[四年前的博客了,当年还真面过百度,可惜那个部门用的是c,非要用c写程序……]
这是一篇沉痛的文章...以此纪念被百度鄙视的经历。
哥从来没有用C写过Web,这也是被鄙视的主要原因之一,补之。
可以通过以下方式:
CGI/FastCGI: FastCGI能让进程常驻内存,不像CGI那样每次都要创建销毁进程,所以会很快,但要注意内存溢出和进程崩溃。
ISAPI/NSAPI:Internet Server API,可以把Dll加载进来,一个Dll可以对应多个响应,这样进程数就少了。NSAPI是啥我就不关心了……
ATL:Active Template Library,支持C++编写ASP和ActiveX
Asp.net: Dot Net framework么,用C++很正常。
OK,下面自己争取写第一个C的Web程序。
从网上找到比较好的一篇教程是:http://www.xxlinux.com/linux/article/development/soft/20090220/15535.html
好了,先写个helloWorld,试试刚下的VC6能不能用:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf ("hello world!");
}
差点包含进来std namespace,现在先写c,不谈c++。泪流满面,hello world,多长时间没写c了....
再造一下:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("Content-type:text/html\n\n");
printf("Hello world from C.");
}
然后部署这个exe到cgi-bin下,浏览器中,泪流满面,哥如今也是用c写过Web的人了……
Content-type:text这个是MIME格式,眼熟啊。
\n\n规定包头和体必须有一个空行!这里不是http协议,是CGI协议,不过很像,哈。
程序还可以写成:
int main()
{
printf("Content-type:text/html\n\n");
int n=0;
if(getenv("CONTENT_LENGTH"))
n = atoi(getenv("CONTENT_LENGTH"));
else
return 0;
for(int i=0; i<n; ++i)
{
putchar(getchar());
putchar('\n');
fflush(stdout);
}
}
这样如果有CONTENT_LENGTH域的值的话,就可以查看POST里面的东东,并打印出来了!
其实像getchar, putchar, getenv这样的小函数,看着还是很亲切的。
CGI用的是标准输入输出流,Web服务器与CGI交换消息用的是环境变量,可以读出来HTTP协议的头之类的东东。这些环境变量是属于这个进程的。
如:REQUEST-METHOD,REMOTE-HOST,SCRIPT-NAME,CONTENT-TYPE,QUERY-STRING等等。
程序改成如下:
int main()
{
printf("Content-type:text/html\n\n");
int n=0;
if(getenv("CONTENT-LENGTH"))
n = atoi(getenv("CONTENT_LENGTH"));
printf("There are %d chars in content<br>", n);
printf("Request method:%s<br>",getenv("REQUEST_METHOD"));
printf("Remote Host:%s<br>",getenv("REMOTE_HOST"));
printf("Script Name:%s<br>",getenv("SCRIPT_NAME"));
printf("Content Type:%s<br>",getenv("CONTENT_TYPE"));
printf("Query String:%s<br>",getenv("QUERY_STRING"));
for(int i=0; i<n; ++i)
{
putchar(getchar());
putchar('\n');
fflush(stdout);
}
}
写一个HTML,放到htdoc下:
<html>
<head>
<title>Test c in CGI</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<form method="GET" action="/cgi-bin/123.exe">
<input type="text" name="input1" width="20"/>
<br />
<input type="submit" value="SUBMIT" />
</form>
</body>
</html>
然后访问浏览器,等到如下:
把方法改成了POST后,得到如下:
There are 0 chars in content
Request method:POST
Remote Host:(null)
Script Name:/cgi-bin/123.exe
Content Type:application/x-www-form-urlencoded
Query String:
鬼魅啊,为啥没有Content_length呢?好吧,认为是只有POST的时候才能去取Content_length,把代码改成:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
printf("Content-type:text/html\n\n");
printf("Request method:%s<br>",getenv("REQUEST_METHOD"));
printf("Remote Host:%s<br>",getenv("REMOTE_HOST"));
printf("Script Name:%s<br>",getenv("SCRIPT_NAME"));
printf("Content Type:%s<br>",getenv("CONTENT_TYPE"));
printf("Query String:%s<br>",getenv("QUERY_STRING"));
if(!strcmp(getenv("REQUEST_METHOD"), "POST"))
{
int n = atoi(getenv("CONTENT_LENGTH"));
printf("There are %d chars in content<br>", n);
for(int i=0; i<n; ++i)
{
putchar(getchar());
fflush(stdout);
}
}
return 1;
}
然后输出为:
Request method:POST
Remote Host:(null)
Script Name:/cgi-bin/123.exe
Content Type:application/x-www-form-urlencoded
Query String:
There are 10 chars in content
input1=234344
好的,这样可以看POST的内容了。
然后,又是心中的一个痛,当年哥被问怎么处理中文字符,哥不知道……哥虽然现在也不知道,但哥快知道了。
先说一下URL Encoding,因为URL只能用ASCII,而且只能用:
[0-9a-zA-Z], "$-_.+!*'(),"<---不包括引号,还有一些保留字。
http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
所以遇到中文之类的就要Encoding了,规则如下
1,加号变为空格
2,%xx索引ASCII码表,xx为16进制,正好覆盖ASCII256个东东
修改代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int htoi(char *s)
{
char *digits= "0123456789ABCDEF";
if (islower (s[0])) s[0]=toupper(s[0]);
if (islower (s[1])) s[1]=toupper(s[1]);
return 16 * (strchr(digits, s[0])-strchr(digits,'0'))+(strchr(digits,s[1])-strchr(digits,'0'));
}
int main()
{
printf("Content-type:text/html\n\n");
printf("Request method:%s<br>",getenv("REQUEST_METHOD"));
printf("Remote Host:%s<br>",getenv("REMOTE_HOST"));
printf("Script Name:%s<br>",getenv("SCRIPT_NAME"));
printf("Content Type:%s<br>",getenv("CONTENT_TYPE"));
printf("Query String:%s<br>",getenv("QUERY_STRING"));
char original[255];
if(!strcmp(getenv("REQUEST_METHOD"), "POST"))
{
int n = atoi(getenv("CONTENT_LENGTH"));
printf("There are %d chars in content<br>", n);
char c;
for(int i=0; i<n; ++i)
{
c = getchar();
original[i]=c;
switch(c)
{
case '&':
c='|';
break;
case '+':
c=' ';
break;
case '%':{
char s[3];
s[0]=getchar();
s[1]=getchar();
s[2]=0;
c=htoi(s);
i+=2;
original[i+1]=s[0];
original[i+2]=s[1];
}
break;
case '=':
c=':';
break;
}
putchar(c);
}
original[i]=0;
}
printf ("<br>Encoded URL is:%s<br>", original);
return 1;
}
这样得到输出:
Request method:POST
Remote Host:(null)
Script Name:/cgi-bin/123.exe
Content Type:application/x-www-form-urlencoded
Query String:
There are 22 chars in content
input1:try another one
Encoded URL is:input1=try+another+one
或者:
input1:||||
Encoded URL is:input1=%烫%C%C%C
这里看到烫,因为数字到字符的转换问题,其实他是两个16进制,input1能转换一些这种字符了。
但是中文还是不能得到完美解决。
留个链接:http://qingbo.net/blog/post144.html
改天继续研究了……