Linux企業級專案實踐之網路爬蟲(28)——爬蟲socket處理

尹成發表於2014-09-04


Socket是程式之間交換資料的機制。這些程式即可以是同一臺機器上的,也可以是通過網路連線起來的不同機器。一旦一個Socket連線建立,那麼資料就能夠雙向傳輸,直到其中一端關閉連線。

 

通常,請求資料的應用程式叫做客戶端Client,而為請求服務叫做伺服器Server。基本上說,首先,伺服器監聽一個埠,並且等待來自客戶端的連線。之後客戶端建立一個,並且嘗試連線伺服器。接著,伺服器接受了來自客戶端的連線,並且開始交換資料。一旦所有的資料都已經通過socket連線傳輸完畢,那麼任意一方都可以關閉連線了。

我們的爬蟲程式只需要client端就夠了。

 

 

int build_connect(int *fd, char *ip, intport)
{
   struct sockaddr_in server_addr;
   bzero(&server_addr, sizeof(struct sockaddr_in));
 
   server_addr.sin_family = AF_INET;
   server_addr.sin_port = htons(port);
   if (!inet_aton(ip, &(server_addr.sin_addr))) {
       return -1;
    }
 
   if ((*fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
       return -1;
    }
 
   if (connect(*fd, (struct sockaddr *)&server_addr, sizeof(structsockaddr_in)) < 0) {
       close(*fd);
       return -1;
    }
 
   return 0;
}
void * recv_response(void * arg)
{
   begin_thread();
 
   int i, n, trunc_head = 0, len = 0;
    char * body_ptr = NULL;
   evso_arg * narg = (evso_arg *)arg;
   Response *resp = (Response *)malloc(sizeof(Response));
   resp->header = NULL;
   resp->body = (char *)malloc(HTML_MAXLEN);
   resp->body_len = 0;
   resp->url = narg->url;
 
   regex_t re;
   if (regcomp(&re, HREF_PATTERN, 0) != 0) {/* compile error */
       SPIDER_LOG(SPIDER_LEVEL_ERROR, "compile regex error");
    }
 
   SPIDER_LOG(SPIDER_LEVEL_INFO, "Crawling url: %s/%s",narg->url->domain, narg->url->path);
 
   while(1) {
       /* what if content-length exceeds HTML_MAXLEN? */
       n = read(narg->fd, resp->body + len, 1024);
       if (n < 0) {
           if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
                /**
                 * TODO: Why always recvEAGAIN?
                 * should we deal EINTR
                 */
                //SPIDER_LOG(SPIDER_LEVEL_WARN,"thread %lu meet EAGAIN or EWOULDBLOCK, sleep", pthread_self());
                usleep(100000);
                continue;
            }
           SPIDER_LOG(SPIDER_LEVEL_WARN, "Read socket fail: %s",strerror(errno));
           break;
 
       } else if (n == 0) {
           /* finish reading */
           resp->body_len = len;
           if (resp->body_len > 0) {
               extract_url(&re,resp->body, narg->url);
           }
           /* deal resp->body */
           for (i = 0; i < (int)modules_post_html.size(); i++) {
               modules_post_html[i]->handle(resp);
           }
 
           break;
 
       } else {
           //SPIDER_LOG(SPIDER_LEVEL_WARN, "read socket ok! len=%d", n);
           len += n;
           resp->body[len] = '\0';
 
           if (!trunc_head) {
                if ((body_ptr =strstr(resp->body, "\r\n\r\n")) != NULL) {
                    *(body_ptr+2) = '\0';
                    resp->header =parse_header(resp->body);
                    if(!header_postcheck(resp->header)) {
                        goto leave; /* moduluesfilter fail */
                    }
                   trunc_head = 1;
 
                    /* cover header */
                    body_ptr += 4;
                    for (i = 0; *body_ptr; i++){
                        resp->body[i] =*body_ptr;
                        body_ptr++;
                    }
                    resp->body[i] = '\0';
                    len = i;
                }
                continue;
           }
       }
    }
 
leave:
   close(narg->fd); /* close socket */
   free_url(narg->url); /* free Url object */
    regfree(&re);/* free regex object */
   /* free resp */
   free(resp->header->content_type);
   free(resp->header);
   free(resp->body);
   free(resp);
 
   end_thread();
   return NULL;
}

相關文章