为多个HTTP连接重用客户端TCP套接字

时间:2011-03-22 04:37:55

标签: c http asynchronous tcp posix

问候所有人。

我在Linux 2.6.29-3.ydl61.3上制作ANSI C多线程www-crawler(HTTP 1.1兼容)并且进展顺利。我在MySQL数据库中有'000个域来收集页面。我可以根据需要以保持活动模式打开爬虫中的任何/所有域。我使用POSIX线程,没有任何竞争或数据竞争。

虽然目标服务器似乎已准备好允许我对每个服务器套接字上的页面发出多个并发或顺序请求(因为每个服务器按预期返回'Connection:Keep-Alive'),但实际上我无法这样做...我每个套接字连接只能获取一个页面...即我可以通过文件描述符向套接字写入典型的HTTP GET请求并读取响应。然后在那之后,我只能写入fd但不再读了!因此,虽然每个域有多个(一些到几百个)URL ...似乎我必须为每次写入/读取(非常浪费内存和缓慢)重新创建到同一服务器的套接字连接,而不是仅创建一个客户端TCP连接并继续重用fd / socket,直到完成域名。

请参阅下面的'netstat --inet -a'的部分输出(请注意,作为不受欢迎的我有多个本地套接字连接到同一个域 - 这些不是每个域并发):

tcp 0 0 gcell1:38614 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell1:34678 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:34768 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:56085 www.hihostels.com:http CLOSE_WAIT tcp 0 0 gcell11:34661 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:34785 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:46660 67.225.194.54:http CLOSE_WAIT tcp 0 0 gcell11:34697 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:37510 www.kenic.or.ke:http CLOSE_WAIT tcp 0 0 gcell11:37516 www.kenic.or.ke:http CLOSE_WAIT tcp 0 0 gcell11:34710 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:34711 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:46677 67.225.194.54:http CLOSE_WAIT tcp 0 0 gcell11:56513 www.kenic.or.ke:http CLOSE_WAIT tcp 0 0 gcell11:57560 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:46634 67.225.194.54:http CLOSE_WAIT tcp 0 0 gcell11:46607 67.225.194.54:http CLOSE_WAIT tcp 0 0 gcell11:46666 67.225.194.54:http CLOSE_WAIT tcp 0 0 gcell11:37526 www.kenic.or.ke:http CLOSE_WAIT tcp 0 0 gcell11:46673 67.225.194.54:http CLOSE_WAIT tcp 0 0 gcell11:34736 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:57557 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:56395 www.kenic.or.ke:http CLOSE_WAIT tcp 0 0 gcell11:34714 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:34669 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:34767 x2web02.myhosting.com:http CLOSE_WAIT tcp 0 0 gcell11:43381 ip-72-167-251-99.ip.se:http CLOSE_WAIT

客户端套接字创建如下(仅部分代码)

if((http_socket_fd = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP))!=SKMG_FAILURE) //typical
...
fcntl(http_socket_fd,SOCK_NONBLOCK); //set to non-block
...
setsockopt(http_socket_fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen); //local TCP keep-alive used
...
while(connect(http_socket_fd, (struct sockaddr *)&http_name, sizeof (struct sockaddr_in)) == (-1))
...
return http_socket_fd;

在此之后我只在fd上使用write / read。它完美地运行,但只进行一次往返。

1)如何为每个域的每个HTTP GET写入/读取重用http_socket_fd,而无需为每个URL创建新的本地TCP套接字?仅将http_socket_fd传递给每个域的每个页面获取调用正是失败的原因。 [CRITICAL]

2)如何在每个域范围的每个套接字的这一个线程上向这些服务器发出异步请求?我运行4个并发线程(我的服务器是双线程),即4个不同的并发域提取。 [NON-CRITICAL]

1 个答案:

答案 0 :(得分:0)

通常的做法是为每个连接创建一个客户端套接字。在线程之间共享套接字也是一个坏主意。

您是否考虑使用提供许多高级功能的libcurl等库,而不是编写自己的HTTP客户端? libcurl站点具有a sample program,可使用多个线程下载内容。另请参阅ZeroMQ,这是一个高性能的消息传递框架。 ZeroMQ套接字可用于连接多个服务器并有效下载数据。 (见The Guide)。