larbin源码分析.jake
larbin源码分析(一) gloabl文件 Connexion结构
larbin源码分析(一) 从gloabl文件分析每一个结构
一本系列主要是分析larbin开源爬虫的源代码,主要思路是先从global文件中的各个重要的结构开始。
1 Connexion 此处为一个结构体
该结构体主要的作用是进行连接服务器的操作。其中析构函数基本不执行,因为此结构是循环利用的,在
程序中保持一定的数量。小扩展:FetchOpen 类主要用来建立连接,而FetchPipe类主要用来进行连接之后的数据交换。
结构体中成员变量
struct Connexion{
char state ; //表示socket的状态EMPTY , CONNECTING , WRITE . OPEN
int pos ; //请求被发送到的位置
FetchError err ; //查询如何终止的
int socket ; // number of the fds
int timeout ; //链接的超时值
LarbinString request ; //http 请求报头
file * parser ; //对下载的网页进行解析
char buffer[maxPageSize] ; //存储下载的网页数据
Connexion() ;
~Connexion() ;
//recycle
void recycle() ; //此处主要进行循环使用
} ;
2 具体成员函数的实现
Connexion::Connexion() //具体将socket的状态变为emptyC
{ //将文件解析句柄变为空
state = emptyC ;
parser = NULL ;
}
Connexion::~Connexion() //保证一旦调用,即报告错误
{
assert(false) ;
}
/*recycle a connexion*/
void Connexion::recycle() //循环使用该结构体
{
delete parser ; //删除解析对象
request.recycle() ; //对LarbinString 调用recycle函数。
}
3 utils包下的connexion.h 和https://www.360docs.net/doc/f412695729.html,的具体代码实现
// Larbin
// Sebastien Ailleret
// 15-11-99 -> 14-12-99
#ifndef CONNEXION_H
#define CONNEXION_H
/* make write until everything is written * return 0 on success, 1 otherwise
* Don't work on non-blocking fds
*/
int ecrire (int fd, char *buf);
/* make write until everything is written * return 0 on success, 1 otherwise
* Don't work on non-blocking fds
*/
int ecrireBuff (int fd, char *buf, int count);
/** Write an int on a fds
* (uses ecrire)
*/
int ecrireInt (int fd, int i);
int ecrireInt2 (int fd, int i);
/** Write an int on a fds
* (uses ecrire)
*/
int ecrireLong (int fd, long i);
/* Write a char on a fds
* return 0 on success, 1 otherwise
* Don't work on non-blocking fds
*/
int ecrireChar (int fd, char c);
#endif// CONNEXION_H
在connexion.h中各个成员函数的作用主要是向套接字中写入数据。
写入操作中主要使用了write 系统调用。
unistd.h中
ssize_t write(int fd , char * buf , int count)
若是发生写错误,则返回值为-1 ,但是若此时的错误状态为EINTR ,则表示是发生了中断操作,此时应该继续进行写操作。
若是当前执行的写操作出现了等待的事情,则不需要报错,应该继续写,直到等待的事情结束。
(1) 误区
write并不是立即执行写操作,而是将数据写入进内核缓冲区。
一般内核区比较稳定,不会出现问题。
(4)下面是connexion的实现代码
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "options.h"
using namespace std ;
/*********************************/ /* various functions for writing */
/* make write until everything is written * return 0 on success, 1 otherwise
* Don't work on non-blocking fds
*/
int ecrire (int fd, char *buf) {
int pos = 0 ;
int len = strlen(buf);
while(pos < len)
if(i == -1)
{
if(errno != EINTR)
{
pos = len + 1 ;
}
}
else{
pos += i ;
}
}
return pos != len ;
}
/* make write until everything is written
* return 0 on success, 1 otherwise
* Don't work on non-blocking fds
*/
int ecrireBuff (int fd, char *buf, int count) { int pos = 0;
while(pos < count)
{
int i = write(fd , buf + pos , count - pos) ;
if(i == -1)
{
case EINTR :
break ;
default:
pos = count + 1 ; perror("buf error") ;
break;
}
}
else
pos += i ;
}
return pos != count;
}
/** Write an int on a fds * (uses ecrire)
*/
int ecrireInt (int fd, int i) { char buf[20];
sprintf(buf, "%d", i); return ecrire(fd, buf);
int ecrireInt2 (int fd, int i) {
char buf[20];
sprintf(buf, "%d%c", i/10, i%10 + '0'); return ecrire(fd, buf);
}
int ecrireInti (int fd, int i, char *f) { char buf[100];
sprintf(buf, f, i);
return ecrire(fd, buf);
}
int ecrireIntl (int fd, long i, char *f) { char buf[100];
sprintf(buf, f, i);
return ecrire(fd, buf);
}
/** Write an int on a fds
* (uses ecrire)
*/
int ecrireLong (int fd, long i) {
char buf[30];
sprintf(buf, "%ld", i);
/* Write a char on a fds
* return 0 on success, 1 otherwise
* Don't work on non-blocking fds
*/
int ecrireChar (int fd, char c) {
int pos = 0;
while (pos < 1) {
int i = write(fd, &c, 1);
if (i == -1) {
if (errno != EINTR) {
pos = 2;
}
} else {
pos += i;
}
}
return pos != 1;
}
(5)综上
Connexion主要处理的是连接相关的信息,其connexion中主要实现的是,向套接字中写入数据。
下一个系列,处理的是LarbinString 相关,该类主要是处理http报头的。
LARBIN源码分析(二) GLOABL文件LARBINSTRING类对象的实现LARBINSTRING类对象的实现
一该类介绍
LarbinString类主要是字符串处理,主要的成员参数是char * chaine 表示字符串的内容存储的指针地址。
还有pos 表示当前string的位置,size表示最大的容量。
成员函数,都为一些添加字符,添加缓冲区的操作。其中的主要的是recycle() ,getString() ,giveStirng()等函数。
二类的头文件
// Larbin
// Sebastien Ailleret
// 20-12-99 -> 05-05-01
#ifndef STRING_HH
#define STRING_HH
#include
#include "types.h"
#include "utils/debug.h"
class LarbinString {
private :
char * chaine ; //内存指针
uint pos ; //当前位置
uint size ; //总共的大小
public :
//Constructor
LarbinString(uint size= STRING_SIZE) ;
~LarbinString() ;
//Recycle this string
void recycle(uint size=STRING_SIZE) ;
//get the char *
//it is deleted when you delete this Stringobject
char * getString() ;
//give a char * : it creates a new one
char * giveString();
//append a char
void addChar(char c) ;
//append a char *
void addString(char * s) ;
//append a buffer
void addBuffer(char * s , uint len) ;
//length of the string
inline uint getLength() {return pos ;}
return chaine[i] ;
}
//change a char
void setChar(uint i , char c) ;
};
#endif// STRING_HH
三实现代码
该代码实质上是实现了,一个string类型,可以自动地增长容量,实现动态地增添操作。
// Larbin
// Sebastien Ailleret
// 20-12-99 -> 10-12-01
#include
#include
#include "options.h"
#include "utils/text.h"
#include "utils/string.h"
using namespace std ;
// Constructor
LarbinString::LarbinString (uint size) {
chaine = new char[size] ;
pos = 0 ;
this->size = size ;
chaine[0] = 0 ;
}
// Destructor
LarbinString::~LarbinString () {
delete [] chaine ;
}
// Recycle this string
void LarbinString::recycle (uint size) {
if(this->size > size) //当大小小于当前的大小时
{
delete [] chaine ;
pos = 0 ;
chaine[0] = 0 ;
}
// get the char *
char *LarbinString::getString () {
return chaine ;
}
/** give a new string (allocate a new one
* the caller will have to delete it
*/
char *LarbinString::giveString () {
return newString(chaine) ;
}
// append a char
void LarbinString::addChar (char c) {
chaine[pos] = c;
pos++ ;
if(pos >= size) //如果当前的
{
char * tmp = new char[2 * size] ;
memcpy(tmp , chaine , pos) ;
delete [] chaine ;
chaine = tmp ;
size *= 2 ;
}
chaine[pos] = 0 ;
}
// append a char *
void LarbinString::addString (char *s) {
uint len = strlen(s);
addBuffer(s, len);
}
// append a buffer
void LarbinString::addBuffer (char *s, uint len) { if (size <= pos + len) {
size *= 2;
if (size <= pos + len) size = pos + len + 1;
char *tmp = new char[size];
memcpy(tmp, chaine, pos);
delete [] chaine;
chaine = tmp;
}
memcpy(chaine+pos, s, len);
// change a char
void LarbinString::setChar (uint i, char c) {
chaine[i] = c;
}
四总结
LarbinString类主要进行的是字符串处理,实质上是自己实现了一个String库。
LARBIN源代码分析<三> URL类分析
LARBIN源代码分析<三> URL类分析
一分析utils包中的url类
该类代表实际中的一个url,成员变量主要有,char * file ,char * host , uint16_t port , int8_t depth, char * cookie
还有一个public 属性的in_addr 表示一个ipv4的地址。
成员函数中主要有一些,比如构造函数,返回url,添加cookie等操作。二实例代码如下
// Larbin
// Sebastien Ailleret
// 15-11-99 -> 14-03-02
/* This class describes an URL */
#ifndef URL_H
#define URL_H
#include
#include
#include
#include
#include "types.h"
bool fileNormalize (char *file);
class url {
private:
char *host;
char *file;
uint16_t port; // the order of variables is important for physical s ize
int8_t depth;
/* parse the url */
void parse (char *s);
/** parse a file with base */
void parseWithBase (char *u, url *base);
/* constructor used by giveBase */
url (char *host, uint port, char *file);
public:
/* Constructor : Parses an url (u is deleted) */
url (char *u, int8_t depth, url *base);
/* constructor used by input */
url (char *line, int8_t depth);
/* Constructor : read the url from a file (cf serialize) */
url (char *line);
/* Destructor */
~url ();
/* inet addr (once calculated) */
struct in_addr addr;
/* Is it a valid url ? */
bool isValid ();
/* print an URL */
void print ();
/* return the host */
inline char *getHost () { return host; }
/* return the port */
inline uint getPort () { return port; }
/* return the file */
inline char *getFile () { return file; }
/** Depth in the Site */
inline int8_t getDepth () { return depth; }
/* Set depth to max if we are at an entry point in the site * try to find the ip addr
* answer false if forbidden by robots.txt, true otherwise */ bool initOK (url *from);
/** return the base of the url
* give means that you have to delete the string yourself */
url *giveBase ();
/** return a char * representation of the url
* give means that you have to delete the string yourself
* buf must be at least of size maxUrlSize
* returns the size of what has been written (not including '\0') */
int writeUrl (char *buf);
/* serialize the url for the Persistent Fifo */
char *serialize ();
/* very thread unsafe serialisation in a static buffer */
char *getUrl();
/* return a hashcode for the host of this url */
uint hostHashCode ();
/* return a hashcode for this url */
uint hashCode ();
#ifdef URL_TAGS
/* tag associated to this url */
uint tag;
#endif// URL_TAGS
#ifdef COOKIES
/* cookies associated with this page */
char *cookie;
void addCookie(char *header);
#else// COOKIES
inline void addCookie(char *header) {}
#endif// COOKIES
};
#endif// URL_H
三代码分析
url中的实现类主要是,创建url,其中创建规则如下:
https://www.360docs.net/doc/f412695729.html,/r/0343/ttt.html
则host为https://www.360docs.net/doc/f412695729.html,, file 为/r/0343/ttt.html
url的构造函数即根据上述规则构建url类。若是含有base url 则新的url 的file为base->file + 新url 的file。
(2)另外url的hash函数即是利用了file 字符串和host字符串。
/* return a hashcode for this url */
uint url::hashCode () {
unsigned int h=port;
unsigned int i=0;
while (host[i] != 0) {
h = 31*h + host[i];
i++;
}
i=0;
return h % hashSize;
}
(3) cookie的处理函数如下
若addCookie(char * head) 中的head字符串是以 set-cookie: 开始的,则将head之后的12个字符
添加到cookie变量中。
四综上:
url 类中的成员变量,char * file ,char * host , port , cookie 能够表示一个url。
并且url类中提供了解析函数,使用户可以根据从网页中爬取的url构造url 类对象。
LARBIN源码分析(四) HASHTABLE类对象的实现
LARBIN源码分析(四)HASHTABLE类对象的实现
一hashTable类对象
作用:爬虫将爬取的url存储在该类对象中,存储方式是,url对象的hashcode,映射到对应的表项中。
其中每一个url,映射成对应table中的一个bit,其中表空间大小为64000000(单位为bit),大小的定义存储在types.h头文件中。
爬去到的url需要在hashTable中进行一次查找,若是不存在,则进行进一步遍历。已经存在,则不需要遍历。
二成员函数
HashTable(bool created ) 构造函数
~HashTable() 析构函数
save() ; 将hashTable存储在文件中。
test(url * U) ;判断对应的url是否在hashTable 中
set(url * u) ; 将hashTable对应的URL ,设置称当前的。
testset(url* u) 如果已经添加返回true 。若是之前已经存在返回false 三实现
(1) HashTable(bool created)
当created为true的时候,表示不需要从文件中读取,直接进行初始化,将table区域全部初始化为0即可。
若created为false的时候,表示需要从文件hashtable.bak中读取存储的数据,将其存放进hashtable类中的table缓冲区中。
(2) save() 函数实现
rename("hashtable.bak", "hashtable.old"); //将hashtable.bak文件存储在临时文件hashtable.old中
int fds = creat("hashtable.bak", 00600); //新创建hashtable.bak文件
if (fds >= 0) {
ecrireBuff(fds, table, hashSize/8); //将hashtable写入文件
close(fds); //关闭操作
}
unlink("hashtable.old"); //对hashtable.old进行解链操作
(3) bool test(url * U) //判断url是否在hashtable中
{
int code = U->hashcode() ; //调用url的hashcode
int index = 1 << code % 8 ;
return table[pos] & index
}
(4) hashTable::set (url *U) //将对应的一个URL插入进hashtable中
{
int code = U->hashcode() ; //调用url的hashcode 函数。
int pos = code / 8 ; //每一个url在hashtable 中即为一个url
int index = 1 << code % 8 ;
table[pos] |= index ;
}
(5) bool hashTable::testSet (url *U) { //若已经存在此url则返回false,不存在则完成插入,然后返回true
int code = U->hashcode() ; //调用url的hashcode 函数。
int pos = code / 8 ; //每一个url在hashtable 中即为一个url
unsigned int index = 1 << code % 8 ;
int res = table[pos] & index ;
table[pos] |= index ;
return !res ;
}
四总结
hashTable 用来存储爬去下来的url,若是已经存在则不进行插入。
每一个url使用一个bit来进行存储。
LARBIN源码分析(五) HASHDUP类对象的实现
LARBIN源码分析(五) HASHDUP类对象的实现
一类的成员变量及主要功能
(1) 成员变量
ssize_t size; //表示hash 表的大小
char *table; //表示hash存储区域
char *file; //表示存储的文件,内存中的hash表可以保存在外部磁盘中
(2) 主要功能
该类和hashTable代码比较相似,但是hashTable处理的是url去重,而hashDup处理的是网页内容的去重,
不会对完全相同的网页进行爬取,但是不保证相似网页的排重。改进的一个方向。
二具体的成员函数
构造函数
hashDup (ssize_t size, char *init, bool scratch); size表示hash 表的大小,单位为bit。
init参数表示hash表存储在磁盘的文件名称。scratch若为true表示重新构建hash表,
若为false,则表示需要从磁盘文件中读取hash表。
~hashDup()函数具体操作为情况table内存。
下面主要讲解网页内容去重的函数
bool hashDup::testSet (char *doc) { //doc应该为网页的具体内容,依次顺序遍历网页内容,对其中A与z之间的字符进行验证
unsigned int code = 0;
char c;
for (uint i=0; (c=doc[i])!=0; i++) {
if (c>'A' && c<'z')
code = (code*23 + c) % size;
}
unsigned int pos = code / 8; //具体的判断函数,若是执行插入返回true,否则返回false
unsigned int bits = 1 << (code % 8);
int res = table[pos] & bits;
table[pos] |= bits;
return !res;
}
save()函数
主要的作用就是,将table区域中的数据,存储在外部磁盘中,进行持久化操作。
三总结
该类为网页内容去重hash函数的具体实现。
LARBIN源码分析(六) LARBIN中线程处理类
LARBIN源码分析(六) LARBIN中线程处理类
一线程类
larbin下的线程操作类,主要在mypthread.h 中定义,实质上是利用宏定义,封装了pthread.h中的系统调用。
一个进程可以有多个线程,每个线程都有自己的处理流程。
二具体实现
typedef void* (*StartFun) (void *);
void startThread (StartFun run, void *arg);
startThread 函数实质上是调用pthread_create 启动一个新的线程。//下面为线程同步的操作
#define mypthread_cond_init(x,y) pthread_cond_init(x,y)
#define mypthread_cond_destroy(x) pthread_cond_destroy(x)
#define mypthread_cond_wait(c,x,y) while (c)
{ pthread_cond_wait(x,y); }
#define mypthread_cond_broadcast(x) pthread_cond_broadcast(x) //下面为线程互斥的操作
#define mypthread_mutex_init(x,y) pthread_mutex_init(x,y)
#define mypthread_mutex_destroy(x) pthread_mutex_destroy(x) #define mypthread_mutex_lock(x) pthread_mutex_lock(x)
#define mypthread_mutex_unlock(x) pthread_mutex_unlock(x)
LARBIN源码分析(七) LARBIN中的2种容器与4个URL队列LARBIN源码分析(七) LARBIN中的2种容器4个URL队列
一larbin中的2中类型的队列
static SyncFifo
static SyncFifo
static PersistentFifo *URLsDisk; //低优先级
static PersistentFifo *URLsDiskWait; //最低优先级
上述4个URL队列的优先级,由上到下依次递减。
四种url队列的具体使用,留待以后分析。
二下面主要分析SyncFifo
该类实际上为一个同步处理的先进先出的队列。
1 类的主要成员变量
uint in, out; //in表示入队指针,out表示出队指针
uint size; //表示队列的大小
T **tab; //指针的指针,T表示类模板pthread_mutex_t lock; //互斥变量
pthread_cond_t nonEmpty; //互斥条件变量
2 一般同样的队列同步框架
(1) 放入队列中的处理
pthread_mutex_lock(&lock)
//放入队列操作
put() //入队操作
pthrad_cond_signal(&lock) //向取队列线程发送信号
pthread_mutex_unlock(&lock)
(2)从队列中取出
pthread_mutex_lock(&lock)
while(empty)
pthread_cond_wait(&nonEmpty) //执行该句的时候,会释放该Mutex锁lock
//取队列处理
pthread_mutex_unlock(&lock)
3 成员函数
(1)构造函数
template
SyncFifo
this->size = size;
in = 0;
out = 0;
mypthread_mutex_init (&lock, NULL);
mypthread_cond_init (&nonEmpty, NULL);
}
(2)~SyncFifo()
析构函数执行tab缓冲区的释放,以及互斥变量,互斥条件变量的销