【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

上面一篇博客当中,我们可以利用单一的线程完成网页的下载。今天,我们打算在此基础上完成多线程的访问和加载操作。使用多线程,倒不是因为这项技术有多牛,主要是因为我们想利用多线程的访问机制,充分利用线程的阻塞时间,这样可以在单位时间内完成更多的下载操作,这样至少可以帮助我们提高一部分效率。

要做到这一点的话,首先要对我们原来的代码进行少许的改造。怎么改造呢?首先就是我们需要把网页分成已访问和待访问两种。一方面,我们对网页进行下载,另一方面我们可以利用网页中链接信息下载新的网页。如果把整个网页看成是一个队列,那么就有一个front、一个end。每一个线程不断地从end中读取文件,获取到http地址之后插入到front之后,整个过程是一个while死循环过程。

/* index to read html file */
static int get_read_index()
{
int index;
WaitForSingleObject(h_index, INFINITE);
if(end == front)
{
ReleaseSemaphore(h_index, 1, NULL);
return -1;
}
index = end ++;
ReleaseSemaphore(h_index, 1, NULL);
return index;
}
/* index to write html file */
static int get_write_index()
{
int index;
WaitForSingleObject(h_index, INFINITE);
index = front ++;
ReleaseSemaphore(h_index, 1, NULL);
return index;
}

上面的过程就是记录索引的过程。当然,我们还需要进行另外一项改造工作,那就是把原来的函数工作模式修改成while(1)的线程工作模式。对于线程来说,就是不断地读取队列、不断地分析文件、不断地插入队列,就是这么简单。

/* download page and its linked pages */
DWORD WINAPI download_page_entry(LPVOID param)
{
char* buffer;
int size;
char name[64];
int index;
while(1)
{
while( -1 == (index = get_read_index()))
{
Sleep(100);
}
memset(name, 0, 64);
sprintf(name, "E:/download/%d.html", index);
if(OK == get_file_content(name, &buffer, &size))
{
get_http_and_download(buffer);
free(buffer);
}
}
}

上面两段代码就是我们所做的基本修改动作。当然还有其他一些注意事项,比如说,注意第一个网页的下载过程、在生成可执行文件的时候一定要选用MultithreadDebugDll选项,编写代码的时候注意进行拷机测试。最后的话,就啥也不说了,贴上源码。当然,还是和原来一样,如果大家希望可以运行执行这段代码的话,一定要在E盘创建一个download目录,其他的就什么也不用管了。

#include <stdio.h>
#include <windows.h>
#include <wininet.h>
#include <assert.h>
#ifdef ERROR
#undef ERROR
#endif
#define U8 unsigned char
#define U32 unsigned int
#define STATUS unsigned int
#define OK 0
#define ERROR (~0L)
#define MAX_BLOCK_SIZE 1024
#define MAX_DOMAIN_NAME_LENGTH 64
#define MAX_THREAD_NUMBER (8)
#pragma comment(lib, "wininet.lib")
static STATUS download_web_page(const char* url, const char* path);
static int end = 0;
static int front = 1;
static HANDLE h_index;
/* index to read html file */
static int get_read_index()
{
int index;
WaitForSingleObject(h_index, INFINITE);
if(end == front)
{
ReleaseSemaphore(h_index, 1, NULL);
return -1;
}
index = end ++;
ReleaseSemaphore(h_index, 1, NULL);
return index;
}
/* index to write html file */
static int get_write_index()
{
int index;
WaitForSingleObject(h_index, INFINITE);
index = front ++;
ReleaseSemaphore(h_index, 1, NULL);
return index;
}
/* get length of html file */
static int get_file_size(const char* path)
{
HANDLE hFile;
int size = 0;
hFile = CreateFile(path, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
size = GetFileSize(hFile, NULL);
CloseHandle(hFile);
}
return size;
}
/* get all data from html file */
static STATUS get_file_content(const char* path, void** pp_buffer, int* size)
{
int length;
char* buffer;
HANDLE hFile;
if(NULL == path)
{
return ERROR;
}
if(NULL == pp_buffer)
{
return ERROR;
}
if(NULL == size)
{
return ERROR;
}
length = get_file_size(path);
if(0 == length)
{
return ERROR;
}
buffer = (char*) malloc(length +1);
if(NULL == buffer)
{
return ERROR;
}
buffer[length] = '\0';
hFile = fopen(path, "r+b");
if(NULL == hFile)
{
free(buffer);
return ERROR;
}
fread(buffer, 1, length, hFile);
fclose(hFile);
*pp_buffer = buffer;
*size = length;
return OK;
}
/* show all http name, sometimes just for debug use */
static void print_http_name(const char* buffer, int size)
{
while(size --)
{
printf("%c", *buffer ++);
}
printf("\n");
}
static void download_linked_page(const char* url, int size)
{
char* data;
char name[64];
print_http_name(url, size);
data = (char*)malloc(size + 1);
if(NULL == data)
{
return;
}
data[size] = '\0';
memmove(data, url, size);
memset(name, 0, 64);
sprintf(name, "E:/download/%d.html", get_write_index());
download_web_page(data, name);
/*  free data memroy, which contained http domain name */
free(data);
}
/* get http form html file, then download it by its name*/
static void get_http_and_download(const char* buffer)
{
const char* prev;
const char* next;
char letter;
int count;
if(NULL == buffer)
{
return;
}
next = buffer;
while(1)
{
next = strstr(next, "http://");
if(NULL == next)
{
break;
}
count = MAX_DOMAIN_NAME_LENGTH;
prev = next;
next += strlen("http://");
while(1)
{
if(!count)
{
break;
}
count --;
letter = *next;
if('"' == letter || '\'' == letter || ')' ==  letter || '>' == letter)
{
break;
}
next ++;
}
if(count)
{
download_linked_page(prev, next - prev);
}
}
}
/* implement page download */
static STATUS download_web_page(const char* url, const char* path)
{
U8 buffer[MAX_BLOCK_SIZE];
U32 iNumber;
FILE* hFile;
HINTERNET hSession;
HINTERNET hUrl;
STATUS result;
hSession = InternetOpen("RookIE/1.0", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if(NULL == hSession)
{
return ERROR;
}
hUrl = InternetOpenUrl(hSession, url, NULL, 0, INTERNET_FLAG_DONT_CACHE, 0);
if(NULL == hUrl)
{
result = ERROR;
goto error1;
}
hFile = fopen(path, "wb");
if(NULL == hFile)
{
result = ERROR;
goto error2;
}
iNumber = 1;
while(iNumber > 0)
{
InternetReadFile(hUrl, buffer, MAX_BLOCK_SIZE -1, &iNumber);
fwrite(buffer, sizeof(char), iNumber, hFile);
}
fclose(hFile);
result = OK;
error2:
InternetCloseHandle(hUrl);
error1:
InternetCloseHandle(hSession);
return result;
}
/* download page and its linked pages */
DWORD WINAPI download_page_entry(LPVOID param)
{
char* buffer;
int size;
char name[64];
int index;
while(1)
{
while( -1 == (index = get_read_index()))
{
Sleep(100);
}
memset(name, 0, 64);
sprintf(name, "E:/download/%d.html", index);
if(OK == get_file_content(name, &buffer, &size))
{
get_http_and_download(buffer);
free(buffer);
}
}
}
/* entry of programme */
int main(int argc, char* argv[])
{
int index;
HANDLE h_download[MAX_THREAD_NUMBER];
h_index = CreateSemaphore(NULL, 1, 1, NULL);
if(NULL == h_index)
{
assert(0);
}
/* 0.html is just the start page */
download_web_page("http://book.dangdang.com", "E:/download/0.html");
for(index = 0; index < MAX_THREAD_NUMBER; index ++)
{
h_download[index] = CreateThread(NULL, 0, download_page_entry, 0, 0, NULL);
if(NULL == h_download[index])
{
assert(0);
}
}
WaitForMultipleObjects(MAX_THREAD_NUMBER, h_download, TRUE, INFINITE);
CloseHandle(h_index);
return 1;
}

搜索引擎的那些事(多线程web遍历)相关推荐

  1. 搜索引擎的那些事(web遍历)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 写搜索引擎对我来说是一件有趣的事情,做的多好谈不上,但是至少可以一步一步做出来.当然做的怎么样 ...

  2. 利用python编写设计多线程web服务器(计算机网络_自顶向下第六版_第二章1和4的编程作业)

    今天翻看自己以前的博客时,发现了这则博客,距今大约也有一年多的时间了,觉得还是蛮有趣的一个作业,于是跟着博客又做了一遍,觉得之前的排版有点不大好,所以此番用markdown 稍微重做些修改更新一下博客 ...

  3. java使用socket实现一个多线程web服务器

    全栈工程师开发手册 (作者:栾鹏) java教程全解 java使用socket实现一个多线程web服务器 除了服务器类,还包括请求类和响应类 请求类:获取客户的HTTP请求,分析客户所需要的文件 响应 ...

  4. 计算机网路实验二 多线程Web服务器的设计与实现

    计算机网路实验二 多线程Web服务器的设计与实现 一. 实验目的及任务 1.实验目的 熟悉简单网络的搭建与基本配置: 熟悉socket.多线程编程: 熟悉JDK编程工具的基本使用: 熟悉HTTP协议: ...

  5. 搜索引擎的那些事(中文分词)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面,我们在介绍搜索引擎的时候也谈到过中文分词.和英文不一样,中文上所有的汉字都是连在一起的, ...

  6. 搜索引擎的那些事(开篇)

    [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 说起搜索引擎,大家肯定都不陌生.至少对于我来说,每日百度的次数不下几十次.在信息的查询和搜索方 ...

  7. 多线程读取同一个文件_前端进阶:多线程Web Workers的工作原理及使用场景

    Web Worker 概述 Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行.在主线程运行的同时,Worker ...

  8. 多线程处理同一批数据_C#中多线程的那点事-多线程的代价

    买椟还珠 上一篇<C#中多线程的那点事儿-Thread入门>,我们掰扯了一下Thread的最基本用法. 我们说到,多线程,可以利用CPU的多个核心,并行执行,从而提升程序的效率. 有个聪明 ...

  9. spring事务在web环境中失效的问题

    今天温习一下spring事务的时候,出现了一种诡异的现象,在java环境中测试事务是可以的.然后到web下测试事务就没用了. spring.xml配置 spring-mvc.xml配置 后来百度发现是 ...

最新文章

  1. 数据结构与算法之美day 6: 如何实现LRU缓存淘汰算法?
  2. Maven项目加载JAR包
  3. qtdesigner怎么实现菜单栏跳转_人人都可写代码-Android零基础编程-app 入口菜单栏实操08...
  4. iPhone销量低迷,或导致苹果放弃自动驾驶项目?
  5. 聊聊spring cloud gateway的SecureHeadersGatewayFilter
  6. Exception raised during rendering: java.lang.System.arraycopy([CI[CII)V
  7. 找到了一些很好的算法书和试题
  8. 使用 ONNX 模型做预测
  9. 历史上那些差点被扼杀的数学天才,考试、偏见都是凶手
  10. HtmlAgilityPack.dll的使用 获取HTMLid
  11. 应用程序平台应用之星:在线手机应用开发平台 不用搭建环境
  12. Java-多线程第三篇3种创建的线程方式、线程的生命周期、线程控制、线程同步、线程通信...
  13. 【学习笔记】子集生成的方法
  14. 总结一下常用web.config公共配置。
  15. 金融数据中心建设模式浅析
  16. feature map理解
  17. python飞机大战实验报告心得_飞机大战实训报告
  18. 招银网络2018笔试分享
  19. ch.ethz.ssh2._MindTerm SSH客户端3.4版已发布
  20. absolute导致的高度塌陷问题——解决方法

热门文章

  1. Retrofit请求数据对错误以及网络异常的处理
  2. Javascript 强制浏览器渲染Dom文档
  3. Log42j 源代码分析:plugin(插件)机制
  4. 线程的同步与互斥,死锁
  5. 关于solaris中 crontab -e 出现数字0的解决办法
  6. xtarbackup 安装
  7. 《Linux shell变量总结回顾》RHEL6(转)
  8. PHP中如何防止直接访问或查看或下载config.php文件
  9. 关于Remoting(续)
  10. 创建线程有几种不同的方式