larbin源碼分析(一) 從gloabl文件分析每一個結(jié)構(gòu)
一 本系列主要是分析larbin開源爬蟲的源代碼,主要思路是先從global文件中的各個重要的結(jié)構(gòu)開始。
1 Connexion 此處為一個結(jié)構(gòu)體
該結(jié)構(gòu)體主要的作用是進行連接服務(wù)器的操作。其中析構(gòu)函數(shù)基本不執(zhí)行,因為此結(jié)構(gòu)是循環(huán)利用的,在
程序中保持一定的數(shù)量。小擴展:FetchOpen 類主要用來建立連接,而FetchPipe類主要用來進行連接之后的數(shù)據(jù)交換。
結(jié)構(gòu)體中成員變量
struct Connexion{
char state ; //表示socket的狀態(tài)EMPTY , CONNECTING , WRITE . OPEN
int pos ; //請求被發(fā)送到的位置
FetchError err ; //查詢?nèi)绾谓K止的
int socket ; // number of the fds
int timeout ; //鏈接的超時值
LarbinString request ; //http 請求報頭
file * parser ; //對下載的網(wǎng)頁進行解析
char buffer[maxPageSize] ; //存儲下載的網(wǎng)頁數(shù)據(jù)
Connexion() ;
~Connexion() ;
//recycle
void recycle() ; //此處主要進行循環(huán)使用
} ;
2 具體成員函數(shù)的實現(xiàn)
Connexion::Connexion() //具體將socket的狀態(tài)變?yōu)閑mptyC
{ //將文件解析句柄變?yōu)榭?br /> state = emptyC ;
parser = NULL ;
}
Connexion::~Connexion() //保證一旦調(diào)用,即報告錯誤
{
assert(false) ;
}
/*recycle a connexion*/
void Connexion::recycle() //循環(huán)使用該結(jié)構(gòu)體
{
delete parser ; //刪除解析對象
request.recycle() ; //對LarbinString 調(diào)用recycle函數(shù)。
}
3 utils包下的connexion.h 和 connexion.cc的具體代碼實現(xiàn)
// 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);
int ecrireInti (int fd, int i, char *f);
int ecrireIntl (int fd, long i, char *f);


/**//** 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中各個成員函數(shù)的作用主要是向套接字中寫入數(shù)據(jù)。
寫入操作中主要使用了 write 系統(tǒng)調(diào)用。
unistd.h中
ssize_t write(int fd , char * buf , int count)
若是發(fā)生寫錯誤,則返回值為-1 ,但是若此時的錯誤狀態(tài)為EINTR ,則表示是發(fā)生了中斷操作,此時應(yīng)該繼續(xù)進行寫操作。
若是當(dāng)前執(zhí)行的寫操作出現(xiàn)了等待的事情,則不需要報錯,應(yīng)該繼續(xù)寫,直到等待的事情結(jié)束。
(1) 誤區(qū)
write并不是立即執(zhí)行寫操作,而是將數(shù)據(jù)寫入進內(nèi)核緩沖區(qū)。
一般內(nèi)核區(qū)比較穩(wěn)定,不會出現(xiàn)問題。
(4)下面是connexion的實現(xiàn)代碼
// Larbin
// Sebastien Ailleret
// 15-11-99 -> 03-05-01

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <ctype.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <errno.h>
#include <iostream>

#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)

{
int i = write(fd , buf + pos, len - pos) ;
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)

{
switch(errno)

{
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);
return ecrire(fd, buf);
}


/**//* 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主要處理的是連接相關(guān)的信息,其connexion中主要實現(xiàn)的是,向套接字中寫入數(shù)據(jù)。
下一個系列,處理的是LarbinString 相關(guān),該類主要是處理http報頭的。