网络爬虫二十二-爬虫socket处理

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;  
}  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值