Linux企业级项目实践之网络爬虫(28)——爬虫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] = '';
 
           if (!trunc_head) {
                if ((body_ptr =strstr(resp->body, "

")) != NULL) {
                    *(body_ptr+2) = '';
                    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] = '';
                    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;
}

原文地址:https://www.cnblogs.com/new0801/p/6176980.html