Larbin 搜索引擎源码赏析——(二)搜索引擎的全局变量类
来源:互联网 发布:创世纪 许文彪 知乎 编辑:程序博客网 时间:2024/04/27 21:59
- // Larbin
- // Sebastien Ailleret
- // 29-11-99 -> 08-03-00
- #include <unistd.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <iostream.h>
- #include <string.h>
- #include <adns.h>
- #include <netdb.h>
- #include <sys/socket.h>
- #include "types.h"
- #include "global.h"
- #include "xutils/text.h"
- #include "xutils/Fifo.h"
- #include "xutils/Site.h"
- #include "xutils/debug.h"
- #include "xutils/MaxedSizedFifo.h"
- #include "xutils/PersistentFifo.h"
- #include "xutils/ConstantSizedFifo.h"
- #include "xutils/ConstantSizedFifoPriority.h"
- ///////////////////////////////////////////////////////////
- // Struct global
- ///////////////////////////////////////////////////////////
- // define all the static variables
- //静态变量的定义过程,其中包括类中的静态成员变量。
- hashTable *global::seen;
- //变量的类型是模板类
- GenericFifo<url> *global::URLsInput;
- GenericFifo<url> *global::URLsInternal;
- Site *global::siteList;
- GenericFifo<Site> *global::okSites;
- GenericFifo<Site> *global::dnsSites;
- Connexion **global::connexions;
- adns_state global::ads;
- ConstantSizedFifoPriority<Connexion> *global::freeConns;
- ConstantSizedFifo<Connexion> *global::userConns;
- Interval *global::inter;
- uint global::depthInSite;
- time_t global::waitDuration;
- char *global::userAgent;
- char *global::sender;
- char *global::headers;
- sockaddr_in *global::proxyAddr;
- bool global::isSpecific;
- char *global::contentType;
- char *global::privilegedExt;
- Vector<char> *global::domains;
- Vector<char> global::forbExt;
- char *global::firstUrl;
- uint global::nb_conn;
- uint global::dnsConn;
- unsigned short int global::httpPort;
- unsigned short int global::inputPort;
- /** Constructor : initialize allmost everything
- * Everything is read from the config file (larbin.conf by default)
- */
- global::global (int argc, char *argv[])
- {
- char *configFile = "larbin.conf";
- bool reload = false; //判断是重新启动的还是第一次启动
- // verification of arguments
- int pos = 1;
- while (pos < argc)
- {
- //argc 大于1,说明有参数
- if (!strcmp(argv[pos], "-c") && argc > pos+1)
- {
- configFile = argv[pos+1]; //#通过参数设置配置文件的名字
- pos += 2;
- }
- else if (!strcmp(argv[pos], "-reload")) //重新启动,从上一次爬行结束时的状态开始
- {
- reload = true; //#设置reload的,具体作用还不清楚。
- pos++;
- }
- else
- {
- break;
- }
- }
- //程序的参数有错误,提示使用方法
- if (pos != argc)
- { //#显示使用方法。
- cerr << "usage : " << argv[0];
- cerr << " [-c configFile] [-reload]/n";
- exit(1);
- }
- //#初始话设置
- // Standard values
- waitDuration = 60; //访问同一服务器,的时间间隔,不能小于30s
- depthInSite = 5; //访问网页的最大深度
- userAgent = "larbin"; //机器人的名称
- sender = "larbin@somewhere.com"; //发送者信息,构造http数据包时用。
- firstUrl = "http://localhost/"; //首先访问的url
- nb_conn = 20; //最大并行数连接数
- dnsConn = 3; //dns最大并行连接数
- httpPort = 8081; // 用通过web看Larbin抓取的统计情况的接口
- inputPort = 1976; //向Larbin添加url等输入信息的telnet接口
- proxyAddr = NULL; //代理服务器地址
- isSpecific = false; //是否是特定搜索
- domains = NULL; //域名限制
- // Read the configuration file
- crash("Read the configuration file"); //在debug.h文件中有宏定义#define crash(s) (cerr << s << "/n")
- parseFile(configFile); //#解析配置文件
- // Initialize everything
- crash("Create global values");
- // Headers
- String strtmp;
- strtmp.addString("/r/nUser-Agent: ");
- strtmp.addString(userAgent);
- strtmp.addString(" ");
- strtmp.addString(sender);
- strtmp.addString("/r/nAccept: text/html/r/n/r/n");
- headers = strtmp.giveString(); //在头文件中定义static char *headers;
- // FIFOs
- //这里的构造函数需要进一步关注
- URLsInternal = new PersistentFifo<url>(fifoFile, reload, this);
- URLsInput = new Fifo<url>;
- inter = new Interval(ramUrls);
- siteList = new Site[siteListSize];
- okSites = new Fifo<Site>;
- dnsSites = new Fifo<Site>;
- seen = new hashTable(!reload); //初始化hash表,定义在头文件中static hashTable *seen;
- userConns = new ConstantSizedFifo<Connexion>(nb_conn); //定义已经使用的连接的队列
- freeConns = new ConstantSizedFifoPriority<Connexion>(nb_conn); //定义free未使用连接的队列
- connexions = new Connexion *[nb_conn]; //定义保存连接信息的结构体数组指针
- for (uint i=0; i<nb_conn; i++) //循环次数为最大连接数
- {
- connexions[i] = new Connexion; //创建连接信息结构体
- freeConns->put(connexions[i]); //将新创建的连接信息结构体,放到free连接队列中
- }
- // init non blocking dns calls
- crash("Start adns"); //初始化dns调用
- adns_initflags flags = adns_initflags (adns_if_nosigpipe | adns_if_noerrprint);
- // adns_initflags (adns_if_nosigpipe);
- adns_init(&ads, flags, NULL);
- }
- /** Destructor : never used because the program should never end !
- */
- global::~global ()
- {
- cerr << "Why he hell do you want to delete global !/n";
- }
- /////////////////////////////////////////////////////////////////
- //
- //函数功能:解析配置文件
- //参数: char *file 配置文件的名称
- //返回值: void
- //注:在构造函数global中调用
- /////////////////////////////////////////////////////////////////
- /** parse configuration file */
- void global::parseFile (char *file)
- {
- int fds = open(file, O_RDONLY);
- if (fds < 0)
- {
- cerr << "cannot open config file/n";
- exit(1);
- }
- char *tmp = readfile(fds); //在text.h文件中定义, 在函数中申请了与文件长度相等的buf
- close(fds); //关闭文件
- // suppress commentary
- bool eff = false;
- //去掉配置文件中的用“#”标记的注释行,把“#”开头的行的数据全部变为空格符
- for (int i=0; tmp[i] != 0; i++)
- {
- switch (tmp[i])
- {
- case '/n':
- eff = false;
- break;
- case '#':
- eff = true; // no break !!!
- default:
- if (eff) tmp[i] = ' ';
- }
- }
- String content; //字符串类string.h文件中有定义
- content.addString(tmp);
- delete [] tmp;
- uint pos = 0;
- char *tok = nextToken(content, &pos); //在text.h文件中定义,函数功能:从字符串中提取下一个单词,nextToken中
- //会重新申请一个空间来保存提取出来的单词,所以在使用完之后要注意释放这个空间
- while (tok != NULL)
- {
- if (!strcasecmp(tok, "UserAgent"))
- {
- //读取配置文件中的用户代理信息
- delete [] tok;
- userAgent = nextToken(content, &pos);
- }
- else if (!strcasecmp(tok, "From"))
- {
- //读取配置文件中的蜘蛛所有者的电子邮件信息
- delete [] tok;
- sender = nextToken(content, &pos);
- }
- else if (!strcasecmp(tok, "startUrl"))
- {
- //读取配置文件中的,第一个爬取的url信息
- delete [] tok;
- firstUrl = nextToken(content, &pos);
- }
- else if (!(tok, "waitduration"))
- {
- //读取配置文件中的,访问同一web服务器的间隔时间
- delete [] tok;
- tok = nextToken(content, &pos);
- waitDuration = atoi(tok); //将字符串转换为整形数字
- delete [] tok;
- }
- else if (!strcasecmp(tok, "proxy"))
- {
- //读取配置文件中的代理服务器信息
- delete [] tok;
- // host name and dns call
- tok = nextToken(content, &pos); //代理服务器的主机名 content为从配置文件中读取的字符串
- struct hostent* hp;
- proxyAddr = new sockaddr_in;
- bzero((char *)proxyAddr, sizeof (struct sockaddr_in)); //保存代理服务器信息的proxyAddr变量清0
- if ((hp = gethostbyname(tok)) == NULL) //返回对应于给定主机名的主机信息。
- {
- endhostent(); //这个函数的作用还不清楚
- cerr << "Unable to find proxy ip address/n";
- exit(1); //退出啊
- }
- else
- {
- proxyAddr->sin_family = hp->h_addrtype;
- memcpy ((char*) &proxyAddr->sin_addr, hp->h_addr, hp->h_length);
- }//((hp = gethostbyname(tok)) == NULL)
- endhostent();
- delete [] tok;
- // port number
- tok = nextToken(content, &pos); //获取端口信息
- proxyAddr->sin_port = htons(atoi(tok));
- delete [] tok;
- }
- else if (!strcasecmp(tok, "pagesConnexions"))
- {
- //读取配置文件中的最大并行连接数的信息
- delete [] tok;
- tok = nextToken(content, &pos);
- nb_conn = atoi(tok);
- delete [] tok;
- }
- else if (!strcasecmp(tok, "dnsConnexions"))
- {
- //读取配置文件中的DNS最大并行连接数的信息
- delete [] tok;
- tok = nextToken(content, &pos);
- dnsConn = atoi(tok);
- delete [] tok;
- }
- else if (!strcasecmp(tok, "httpPort"))
- {
- //读取配置文件中留给使用者的查看抓取情况的web接口
- delete [] tok;
- tok = nextToken(content, &pos);
- httpPort = atoi(tok);
- delete [] tok;
- }
- else if (!strcasecmp(tok, "inputPort"))
- {
- //读取配置文件中端口号,该端口号用于向Larbin添加url等输入信息的telnet接口
- delete [] tok;
- tok = nextToken(content, &pos);
- inputPort = atoi(tok);
- delete [] tok;
- }
- else if (!strcasecmp(tok, "depthInSite"))
- {
- //读取配置文件中的,爬虫爬去的深度
- delete [] tok;
- tok = nextToken(content, &pos);
- depthInSite = atoi(tok);
- delete [] tok;
- }
- else if (!strcasecmp(tok, "specificSearch"))
- {
- //读取配置文件中设置爬取某种格式文件的信息,如specificSearch audio/mpeg .mp3 end专门爬去mp3文件
- delete [] tok;
- if (isSpecific)
- {
- cerr << "Bad configuration file : Two specificSearch fields/n";
- exit(1);
- }//end if
- isSpecific = true;
- contentType = nextToken(content, &pos); //设置制定搜索的内容类型
- privilegedExt = nextToken(content, &pos); //设置相对应的文件后缀名
- if (privilegedExt != NULL && !strcasecmp(privilegedExt, "end"))
- {
- //当privilegedExt是结束符end是,将privilegedExt置空
- delete [] privilegedExt;
- privilegedExt = NULL;
- }
- else
- {
- tok = nextToken(content, &pos);
- if (tok == NULL || strcasecmp(tok, "end"))
- {
- //在读取一个字字符串,如果是NULL或不是end,则配置文件异常,推出
- cerr << "Bad configuration file : no end to specificSearch/n";
- exit(1);
- }//end (tok == NULL || strcasecmp(tok, "end"))
- delete [] tok;
- }//end if (privilegedExt != NULL && !strcasecmp(privilegedExt, "end"))
- }
- else if (!strcasecmp(tok, "limitToDomain"))
- {
- //读取配置文件中,域名限制相关的信息
- delete [] tok;
- manageDomain(content, &pos); //本类的成员变量
- }
- else if (!strcasecmp(tok, "forbiddenExtensions"))
- {
- //读取配置文件中,禁止爬取的文件类型的信息
- delete [] tok;
- manageExt(content, &pos); //本类的成员变量
- }
- else
- {
- cerr << "bad configuration file : " << tok << "/n";
- exit(1);
- }
- tok = nextToken(content, &pos);
- }//end while
- }//end function
- ////////////////////////////////////////////////////////////////////////
- //
- //函数功能:设置域范围
- //参数: String &content 所包含配置信息的字符串
- // uint *pos 当前需要处理的字符的位置
- //注:被parseFile函数调用
- //在parseFile函数中调用
- //////////////////////////////////////////////////////////////////////////////
- /** read the domain limit */
- void global::manageDomain (String &content, uint *pos)
- {
- char *tok = nextToken(content, pos); //取一个子字符串
- if (domains == NULL)
- {
- domains = new Vector<char>; //使用模板类创建字符串数组
- }//end if
- while (tok != NULL && strcasecmp(tok, "end")) //字符串不等于“end”,即没有结束
- {
- domains->addElement(tok); //这里的vector不是STL中的模板类,而是作者自己定义的模板,
- //不妨学习一下数组模板的实现过程
- //tok是一个字符创指针,将这个指针添加到domains的数组变量中,实际上domains相当于一个二维数字
- tok = nextToken(content, pos);
- }//end while
- if (tok == NULL)
- {
- cerr << "Bad configuration file : no end to limitToDomain/n";
- exit(1);
- }
- else
- {
- delete [] tok;
- } //end if_else
- }
- /** read the forbidden extensions */
- /////////////////////////////////////////////////////////////////
- //
- //函数功能:设置禁止爬去的文件扩展名类型,实现方法与上个函数类似
- //参数: String &content 所包含配置信息的字符串
- // uint *pos 当前需要处理的字符的位置
- //返回值:void
- //在parseFile函数中调用
- ///////////////////////////////////////////////////////////////////
- void global::manageExt (String &content, uint *pos)
- {
- char *tok = nextToken(content, pos);
- while (tok != NULL && strcasecmp(tok, "end"))
- {
- forbExt.addElement(tok);
- tok = nextToken(content, pos);
- }//end while
- if (tok == NULL)
- {
- cerr << "Bad configuration file : no end to forbiddenExtensions/n";
- exit(1);
- }
- else
- {
- delete [] tok;
- }//end if_else
- }
- /** connect to this server using connection conn
- * return the state of the socket
- */
- ////////////////////////////////////////////////////////////////////////
- //
- //函数功能:获得代理服务器的套接字 socket
- //参数:Connexion *conn 保存连接信息的结构体
- //返回值:char 返回连接的状态,EMPTY CONNECTING WRITEOPEN几种
- //
- ////////////////////////////////////////////////////////////////////////
- char global::getProxyFds (Connexion *conn)
- {
- assert (proxyAddr != NULL);
- int fd = socket(AF_INET, SOCK_STREAM, 0); //创建套接字
- if (fd < 0)
- {
- //创建失败返回EMPTY
- return EMPTY;
- }
- conn->socket = fd;
- for (;;)
- {
- fcntl(fd, F_SETFL, O_NONBLOCK); //函数的作用不清楚
- if (connect(fd, (struct sockaddr*) proxyAddr, //代理服务器的ip地址
- sizeof(struct sockaddr_in)) == 0) //连接代理地址
- {
- // success
- //连接成功返回状态 WRITE
- return WRITE;
- }
- else if (errno == EINPROGRESS) //ein progress
- {
- // would block
- //在非阻塞状态下会有这种情况
- return CONNECTING; //connecting
- }
- else
- {
- // error
- (void) close(fd);
- return EMPTY;
- }//end if_else
- }//end for
- }//end function
- ///////////////////////////////////////////////////////////
- // Struct Connexion
- ///////////////////////////////////////////////////////////
- /** put Connection in a coherent state
- */
- ////////////////////////////////////////////////////////
- //
- //函数功能:构造函数
- //
- //
- ///////////////////////////////////////////////////////////
- Connexion::Connexion ()
- {
- state = EMPTY;
- parser = NULL;
- }
- /** Destructor : never used : we recycle !!!
- */
- ///////////////////////////////////////////////////////////////
- //
- //函数功能:析构函数
- //
- //
- ///////////////////////////////////////////////////////////////////
- Connexion::~Connexion ()
- {
- cerr << "My god, someone tries to delete a Connexion !/n";
- }
- /** Recycle a connexion
- */
- void Connexion::recycle ()
- {
- delete parser;
- request.recycle();
- }
全局变量类的头文件:
global.h文件
- // Larbin
- // Sebastien Ailleret
- // 18-11-99 -> 15-04-00
- /* This class contains all global variables */
- #ifndef GLOBAL_H
- #define GLOBAL_H
- #include <adns.h>
- #include <time.h>
- #include "xfetcher/file.h"
- #include "xfetcher/hashTable.h"
- #include "xutils/url.h"
- #include "xutils/Vector.h"
- #include "xutils/GenericFifo.h"
- #include "xutils/string.h"
- #include "xinterf/output.h"
- #include "xutils/ConstantSizedFifo.h"
- #include "xutils/ConstantSizedFifoPriority.h"
- // define for the state of a connection
- #define EMPTY 0
- #define CONNECTING 1
- #define WRITE 2
- #define OPEN 3
- class Site;
- class Interval;
- /** This represent a connection : we have a fixed number of them
- * fetchOpen links them with servers
- * fetchPipe reads those which are linked
- */
- struct Connexion
- {
- char state; // what about this socket : EMPTY, CONNECTING, WRITE, OPEN 连接状态
- int pos; // What part of the request has been sent //作用还不太清楚
- // and how much have we received
- // pos is also used for reporting fetchError (awful hack)
- int socket; // number of the fds 套接字
- time_t timeout; // timeout for this connexion //超时设置
- String request; // what is the http request 请求字符串
- file *parser; // parser for the connexion (is it a robots.txt or an html file)
- //文件指针
- /** Constructor */
- Connexion ();
- /** Dectructor : it is never used since we reuse connections */
- ~Connexion ();
- /** Recycle a connexion
- */
- void recycle (); //完成的工作,释放文件指针(delete),重新申请request字符串
- };
- class global
- {
- public:
- /** Constructor : see global.cc for details */
- global (int argc, char * argv[]);
- /** Destructor : never used */
- ~global ();
- /** List of pages allready seen (one bit per page) */
- static hashTable *seen;
- /** URLs for the sequencer : each one has a different priority */
- static GenericFifo<url> *URLsInput; //保存url的一个队列
- /** This one has the lowest priority */
- static GenericFifo<url> *URLsInternal;
- /** hashtable of the site we accessed (cache) */
- static Site *siteList;
- /** Sites which have at least one url to fetch */
- static GenericFifo<Site> *okSites; //在变量在Site.cc 的void Site::putUrl (url *u) 函数中使用
- /** Sites which have at least one url to fetch
- * but need a dns call
- */
- static GenericFifo<Site> *dnsSites;
- /** Informations for the fetch
- * This array contain all the connections (empty or not)
- */
- static Connexion **connexions;
- /** Internal state of adns */
- static adns_state ads;
- /** free connection for fetchOpen : connections with state==EMPTY */
- static ConstantSizedFifoPriority<Connexion> *freeConns;
- /** free connection for fetchOpen : connections waiting for end user */
- static ConstantSizedFifo<Connexion> *userConns;
- /** Sum of the sizes of a fifo in Sites */
- static Interval *inter; //Interval类在Sit.h文件中有定义
- /** How deep should we go inside a site */
- static uint depthInSite; //访问网页的最大深度
- /** how many seconds should we wait beetween 2 calls at the same server
- * 0 if you are only on a personnal server, >=30 otherwise
- */
- static time_t waitDuration; //访问相同的服务器的时间间隔
- /** Name of the bot */
- static char *userAgent; //机器人的名称
- /** Name of the man who lauch the bot */ //发起
- static char *sender; //发送者信息,构造http数据包时用。
- /** http headers to send with requests
- * sends name of the robots, from field...
- */
- static char *headers; //存放User-Agent.......等等一些列的字符串
- /* internet address of the proxy (if any) */
- static sockaddr_in *proxyAddr; //代理服务器地址信息
- /** connect to this server through a proxy using connection conn
- * return >0 in case of success (connecting or connected), 0 otherwise
- */
- static char getProxyFds (Connexion *conn);
- /** Are we doing a specific search
- */
- static bool isSpecific; //是否做特定的搜索,文件后缀的限制,域名的限制
- /** What is the content-type we look for
- */
- static char *contentType; //如果specificSearch audio/mpeg .mp3 end在配置文件中, contentType为audio/mpeg
- /** Is there a privileged extension //权限扩展
- */
- static char *privilegedExt; //如果specificSearch audio/mpeg .mp3 end在配置文件中, privilegedExt为.mp3
- /** Limit to domain */
- static Vector<char> *domains; //域名限制
- /** forbidden extensions
- * extensions which are allways to avoid : .ps, .pdf...
- */
- static Vector<char> forbExt;
- /** First URL to fetch : initiate the search */
- static char *firstUrl; //首先访问的url
- /** number of parallel connexions 并行
- * your kernel must support a little more than nb_conn file descriptor
- * select should be able to handle as many fds
- */
- static uint nb_conn; //最大并行连接数
- /** number of parallel dns calls */
- static uint dnsConn; //dns最大并行连接数
- /** port on which is launched the http statistic webserver */
- static unsigned short int httpPort; //默认httpPort = 8081; 用通过web看Larbin抓取的统计情况
- /** port on which input wait for queries */
- static unsigned short int inputPort; //默认值是inputPort = 1976; 向Larbin添加url等输入信息的telnet接口
- /** parse configuration file */ //解析配置文件
- static void parseFile (char *file);
- /** read the domain limit */
- static void manageDomain (String &content, uint *pos);
- /** read the forbidden extensions */
- static void manageExt (String &content, uint *pos);
- };
- #endif // GLOBAL_H
全局变量类的CC文件
global.cc文件
- Larbin 搜索引擎源码赏析——(二)搜索引擎的全局变量类
- Larbin 搜索引擎源码赏析——(一)搜索引擎的main函数
- Larbin 搜索引擎源码赏析——(六)一个自定义的数组模板
- Larbin 搜索引擎源码赏析——(四)后台控制爬虫的接口,一个极为简单的telnet服务器
- Larbin 搜索引擎源码赏析——(五)为二次开发用户提供的进一步处理网页的接口函数
- Larbin 搜索引擎源码赏析——(三)用来反馈爬虫状态微型web服务器
- Larbin 一种高效的搜索引擎爬虫工具
- 毕业设计源码——搜索引擎
- Larbin 一种高效的搜索引擎爬虫工具(转)
- 搜索引擎(二)
- 搜索引擎入门(二)
- 实现自己的搜索引擎(二)
- 源码搜索引擎
- 世界搜索引擎——主要国外(二)
- 这就是搜索引擎(二)—检索排序、链接分析
- 这就是搜索引擎(三)——搜索引擎优化
- 搜索引擎优化编程(二)——友好的URL地址
- 搜索引擎的基本原理(以及MetaSeeker搜索引擎)
- HTML&&JS
- 久违了!
- [C学习笔记].编码规范
- __autoload()函数
- 自己写的一个加密,解密(AES)组件
- Larbin 搜索引擎源码赏析——(二)搜索引擎的全局变量类
- MOSS开发常见错误信息
- oracle学习笔记(六)-- 相关语法
- Hide Delegate(隐藏委托关系)
- C#.net 支付宝接口
- 幸福的定义是嘛?
- eclipse 无法运行main函数类的解决办法
- asp 过滤非法字符函数
- ashx是什么文件,如何创建