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; }