-- 1 ------------- 2 --------------------- 3 ------------------- 4 ----
(1) 最左是一个用户, 向浏览器的表单中输入数据.
(2) 中间偏左是浏览器, 它把用户请求通过 http 数据提交给 myso.cgi 所在 webserver.
(3) Web服务器执行 myso.cgi. 然后 myso.cgi 会连接远程的数据服务器(能提供搜索功能),
myso.cgi 收到查询结果后, 分析查询结果. 重新构造自己的查询结果.
(4) Data Server 其实就是个能提供搜索功能的服务器, 它本身就是个搜索引擎.
我们这里是借用它的数据源, "打磨" 自己的搜索引擎.
好了, 经过上面的分析可以已经能看出整个处理过程了.
可能有人会说, 这是一种 "盗链". 是的, 必须承认这是一种盗链, 不过本示例还解决了
防 "盗链" 的相关技术(见下文). 这里就是为什么标题中称为"打磨"的本意.
4. 原码分析: (1) 源码中设及 API 说明等的相关说明:
1) <% %> - 用于在 HTML 等模板文件中嵌入 C 程序 (即 CSP 语句)
2) @g - 标记块, 用于在 HTML 等模板文件中 嵌入 C 函数等全局性信息.
3) @b - 将被 CSP 页开始处执行.
4) G() - 函数, 从用户提交的表单中获取输入的值, 相关于 getParameter() 函数.
5) 其它 API 请参阅相关手册.
(2) 源码可以分为三部分理解:
1) html 部分 (1-71 行), 这部分主要是 html 模板
2) @b 部分 (73-165 行), 这部分是当请求提交给该页面时, 被首先执行. 即: begin
3) @g 部分 (167-328行), 这部分定义了与页面相关的全局的函数,
可以在程序任意处调用. 即: global.
(3) @b 部分(73-165 行):
1) 74 - 87 行, 说明了该函数需要包含的 C 程序的头文件, 注意用 @include 不是 #include
2) 88 - 94 定义了, C 的局变量
3) 96 - 123 用于处理五笔编码和汉语拼音的查询.
4) 128- 164 用于处理五 IP地址所在地和域名 的查询, 与(3) 的流程类似.
5) 97 - 98 确认是用提交的数据不为空, 并且成功连接远程序数据服务器
6) 103-110 手工构造 HTTP 的 POST 请求, 以向远程服务器提交查询.
7) 112-116 发送 http 请求并接收应答到一个 buffer 中.
8) 117-121 从应答中分离出来我们需要的数据, 应答的是一个 html 文件.
9) 160-164 如果连接错误, 则根据错误类型构造错误信息并存入 errmsg 中.
(4) html 部分(1-71 行):
1) 56 - 60 行, 通过 <% %> 嵌入一断 C 程序的判断语句,
如果是错误则输出错误到当前处, 否则把查询结果输出到当前处.
2) 69 行的 <% //=buff %> 是调试用的, 已被 // 注释掉了.
可以把 // 去掉以把来自数据服务器的全部应答打印出来.
3) 其它的就不细说了.
(5) @g 部分 (167-328行)
1) 这里定义了 6 个函数
int SocketInit();
int get_proxy(char * proxy_ip, short * port);
char * make_error(char * errmsg);
int connect_query_host(char * hostname, char * errmsg);
int send_http_req(int sock, char * http_req);
int recv_http_req(int sock, char * http_req, int maxlen);
2) 前两个是
windows 专用.
SocketInit() 用于初始化 socket
get_proxy() 从注册表中读取 IE 的代理设置.
3) connect_query_host() 用于连接远程数据服务器,
当设置代理时, 先尝试使用代理连接.
4) send_http_req() 和 recv_http_req() 发送和接收 http 请求.
(6) 附源码
001 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
002 "http://www.w3.org/TR/html4/loose.dtd">
003 <!--
004 源码来自: http://www.eybuild.com
005 支持平台: Unix/
Windows006 Unix编译: make clean all
007 变更请通知作者: eybuild@hotmail.com
008 -->
009 <html>
010 <head>
011 <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
012 <title>五笔编码查询</title>
013 <link href="/css/tq.css" rel="stylesheet" type="text/css">
014 <script language="javascript" src="<% =romPrefix(NULL) %>/js/myso.js"></script>
015 </head>
016 <style><!--
017 body,td,a,p,{font-family:arial,sans-serif;font-size:14px}
018 --></style>
019 <body>
020 <p>
021 <center><img src="<% =romPrefix(NULL) %>/img/myso.jpg"></center>
022 <table width="430" border="0" align="center" cellspacing="0";">
023 <tr>
024 <td colspan="3"> </td>
025 </tr>
026 <tr>
027 <td colspan="3"><strong>五笔编码&汉语拼音查询</strong></td>
028 </tr>
029 <form name="form1" method="post" action="<% =thisCgiPrefix() %>" onsubmit="return check()">
030 <tr>
031 <td width=135>请输入汉字:</td>
032 <td><input name="querykey" type="text" size="20" value=""></td>
033 <td><input type="submit" name="wubiquery" value="开始查询""></td>
034 </tr>
035 </form>
036 <tr>
037 <td colspan="3"> </td>
038 </tr>
039 <tr>
040 <td colspan="3"><strong>IP地址所在地/域名查询</strong></td>
041 </tr>
042 <form name="ipform" method=post action="<% =thisCgiPrefix() %>" onsubmit="return checkIP();">
043 <tr>
044 <td>请输入IP或域名:</td>
045 <td><input type="text" name="ip" size="20">
046 <td><input type="submit" name="ipquery" value="开始查询">
047 <input TYPE="hidden" name="action" value="2">
048 </tr>
049 </form>
050 <tr>
051 <td colspan="3"> </td>
052 </tr>
053 </table>
054 <table width="430" border="0" align="center" cellspacing="0">
055 <tr>
056 <td><font color=red><% if (!isblankstr(errmsg)) /* report error */
057 print("<b>查询失败:</b> %s", errmsg);
058 else
059 print("%.*s", qlen, qstart); /* output query result */
060 %></font>
061 </td>
062 </tr>
063 <tr><td> </td></tr>
064 <tr><td><center><a href="http://www.eybuild.com" target=_blank>源码下载<A> |
065 <a href="maito=eybuild@hotmail.com" target=_blank>联系作者<A> |
066 <a href="http://www.eybuild.com" target=_blank>更多信息<A> </center></td></tr>
067 <tr><td><center>(来自: http://www.eybuild.com)</center></td></tr>
068 </table>
069 <xmp><% //=buff %></xmp>
070 </body>
071 </html>
072
073 <% @b
074 @include <undef.h>
075 @ifdef WIN32
076 @include <winsock2.h>
077 @define close closesocket
078 @else
079 @include <unistd.h>
080 @include <errno.h>
081 @include <sys/types.h>
082 @include <sys/socket.h>
083 @include <netinet/in.h>
084 @include <arpa/inet.h>
085 @include <netdb.h>
086 @endif /* WIN32 */
087 @include <ebdef.h>
088 int sock = 0;
089 char buff[4096] = "";
090 int maxlen = sizeof(buff);
091 char * qstart = ""; /* query result start address */
092 int qlen = 0; /* query result length */
093 char errmsg[256] = "";
094 int ret = OK;
095
096 /* wubi query */
097 if (!isblankstr(G("querykey")) &&
098 (sock = connect_query_host("qq.ip138.com", errmsg)) > 0)
099 {
100 char req_buf[1024] = "";
101 char query[256] = "";
102
103 /* make query and http header */
104 sprintf(query, "querykey=%s", urlEncode(G("querykey")));
105 sprintf(req_buf, "POST http://qq.ip138.com/wb/wb.asp? HTTP/1.0\r\n"
106 "Content-Type: application/x-www-form-urlencoded\r\n"
107 "Content-Length: %d\r\n"
108 "Host: qq.ip138.com\r\n"
109 "\r\n"
110 "%s", strlen(query), query);
111
112 /* send ==> receive ==> parse result */
113 if ((ret=send_http_req(sock, req_buf)) > 0)
114 {
115 if ((ret=recv_http_req(sock, buff, sizeof(buff))) > 0)
116 {
117 /* separate result */
118 if (NULL != (qstart=strstr(buff, "<p align=\"center\">\r\n")))
119 {
120 qlen = strstr(qstart, "</p>") - qstart;
121 }
122 }
123 }
124
125 close(sock);
126 }
127
128 /* ip query */
129 if (!isblankstr(G("ip")) &&
130 (sock = connect_query_host("www.ip138.com", errmsg)) > 0)
131 {
132 char req_buf[1024] = "";
133 char query[256] = "";
134
135 /* make query and http header */
136 sprintf(query, "ip=%s&action=2", G("ip"));
137 sprintf(req_buf, "POST http://www.ip138.com/ips8.asp HTTP/1.0\r\n"
138 "Referer: http://www.ip138.com/\r\n"
139 "Content-Type: application/x-www-form-urlencoded\r\n"
140 "Content-Length: %d\r\n"
141 "Host: www.ip138.com\r\n"
142 "\r\n"
143 "%s", strlen(query), query);
144
145 /* send ==> receive ==> parse result */
146 if ((ret=send_http_req(sock, req_buf)) > 0)
147 {
148 if ((ret=recv_http_req(sock, buff, sizeof(buff))) > 0)
149 {
150 if (NULL != (qstart=strstr(buff, "<ul class=\"ul1\">")))
151 {
152 qlen = strstr(qstart, "</td>") - qstart;
153 }
154 }
155 }
156
157 close(sock);
158 }
159
160 /* make error message */
161 if (sock < 0 || ret < 0)
162 {
163 make_error(errmsg);
164 }
165 %>
166
167 <% @g
168
169 #ifdef WIN32
170 char * make_error(char * errmsg)
171 {
172 int errcode;
173 LPVOID lpMsgBuf;
174
175 if (OK == (errcode=GetLastError()))
176 return "Ready";
177
178 FormatMessage(
179 FORMAT_MESSAGE_ALLOCATE_BUFFER |
180 FORMAT_MESSAGE_FROM_SYSTEM |
181 FORMAT_MESSAGE_IGNORE_INSERTS,
182 NULL,
183 errcode,
184 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
185 (LPTSTR) &lpMsgBuf,
186 0,
187 NULL
188 );
189
190 // Process any inserts in lpMsgBuf.
191 sprintf(errmsg, "%d: %s", errcode, lpMsgBuf);
192
193 // Free the buffer.
194 LocalFree( lpMsgBuf );
195
196 return errmsg;
197 }
198
199 int SocketInit()
200 {
201
202 WSADATA wsaData;
203
204 if ( WSAStartup( 0x101, &wsaData ) ) {
205 fprintf( stderr, "Could not initialize WinSock\n" );
206 return ERROR;
207 }
208
209 if ( 0x101 != wsaData.wVersion ) {
210 fprintf( stderr, "Version %x not supported\n", wsaData.wVersion );
211 return ERROR;
212 }
213
214 return OK;
215 }
216
217 /* try to get proxy from
windows register */
218 int get_proxy(char * proxy_ip, short * port)
219 {
220 HKEY hkey;
221 DWORD d=sizeof(char);
222 char * path = "Software\\Microsoft\\
Windows\\CurrentVersion\\Internet Settings";
223 unsigned long type;
224 unsigned char data[256] = "";
225 unsigned long dlen = sizeof(data);
226 char * pstr = NULL;
227
228 proxy_ip[0] = '\0';
229 if (ERROR_SUCCESS==RegOpenKeyEx(HKEY_CURRENT_USER, path, 0, KEY_READ, &hkey))
230 {
231 if (ERROR_SUCCESS!=RegQueryValueEx(
232 hkey, "ProxyServer", 0, &type, (unsigned char*)data, &dlen))
233 {
234 RegCloseKey(hkey);
235 return -1;
236 }
237
238 if (NULL != (pstr=strchr(data, ':')))
239 {
240 sprintf(proxy_ip, "%.*s", pstr-data, data);
241 *port = (short)atoi(pstr+1);
242 }
243
244 RegCloseKey(hkey);
245 return 0;
246 }
247
248 return -1;
249 }
250
251 #else /* WIN32 */
252 /* for unix */
253 char * make_error(char * errmsg)
254 {
255 strcpy(errmsg, strerror(errno));
256
257 return errmsg;
258 }
259 #endif /* WIN32 */
260
261
262 int connect_query_host(char * hostname, char * errmsg)
263 {
264 int sock = 0;
265 struct sockaddr_in sa;
266 char dstip[20] = "";
267 short port = 0;
268
269 #ifdef WIN32
270 if (SocketInit() < 0)
271 return ERROR;
272
273 memset(&sa, 0, sizeof(sa));
274 sa.sin_family=AF_INET;
275
276 /* by proxy */
277 if (!get_proxy(dstip, &port) && !isblankstr(dstip))
278 {
279 sa.sin_port = htons(port);
280 sa.sin_addr.s_addr = inet_addr(dstip);
281 }
282 /* by domain name */
283 else
284 #endif /* WIN32 */
285 {
286 struct hostent * ht = gethostbyname(hostname);
287
288 /* parse domain error */
289 if (NULL == ht)
290 return ERROR;
291
292 sa.sin_port = htons(80);
293 sa.sin_addr.s_addr = (*(struct in_addr *)ht->h_addr_list[0]).s_addr;
294 }
295
296 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
297 return ERROR;
298
299 if (connect(sock, (struct sockaddr *)&sa, sizeof(struct sockaddr_in)) < 0)
300 return ERROR;
301
302 return sock;
303 }
304
305
306 int send_http_req(int sock, char * http_req)
307 {
308 int len;
309
310 len = send(sock, http_req, strlen(http_req), 0);
311
312 return len;
313 }
314
315
316 int recv_http_req(int sock, char * http_req, int maxlen)
317 {
318 int len;
319 int dlen = 0;
320
321 while(dlen < maxlen-1 && (len=recv(sock, http_req+dlen, maxlen-dlen-1, 0)) > 0)
322 {
323 dlen += len;
324 }
325
326 return dlen;
327 }
328 %>