如何编写代码以并行方式下载?

时间:2012-01-19 02:29:16

标签: c pthreads fork concurrent-programming

我想获得一个文件的并行下载,例如,如果文件大小为54 kb,我想将10kb的块下载文件的内容。

另外,我一次只能提出5个请求。 但怎么样?我想过使用fork(),但不是真的理解如何。

1-10第一次请求
11-20秒请求
21-30第三次请求
31-40第四次请求
41-50第五次请求


51-54等到过去一个请求结束。然后它将被执行。

我不关心获取数据的方法(recv等)。我只是想知道如何实现并发方法? (如果我可以使用fork()更好)

1 个答案:

答案 0 :(得分:0)

有一些现成的软件库可以提供此功能。我能想到的主要是卷曲。您可以轻松了解 curl multi here

除非你有充分的理由(例如改善技术世界或学术研究),否则通常最好避免重新发明轮子。

为了学术研究,并且因为没有"仅链接"答案就足够了,我将详细阐述人们可以采用的多路复用插座方式之一。

非阻塞套接字

第一种,也是目前最便携的方法是使用非阻塞套接字和/或非阻塞套接字调用,但实现它很重要(特别是当使用非阻塞套接字调用<时/ em>而不是将O_NONBLOCK设置为文件描述符:某些内容仍将阻止。例如,除非您将文件描述符设置为非阻塞模式,否则您无法立即返回connect,当然getaddrinfo(以及类似的标准名称解析函数)将阻塞,太

当您使用非阻塞文件或调用函数时,函数将立即返回。如果没有准备好数据,他们会通过返回值来表明这一点。如果有数据准备好再次处理,它将通过返回值显示。

有两种方法(我知道)确保非阻塞套接字调用(包括connect)。

  1. 对于类Unix系统,请致电fcntl(socket_fd, fcntl(socket_fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK)。在此之后,对readwriteacceptconnect的所有来电都会立即返回。 connect有一些错误代码(errno)专门针对此问题,例如您{&#1}},EALREADYEINPROGRESSEISCONN 39; ll想要检查,因为当你启用非阻塞时,某些错误返回值实际上是伪装的成功返回值;你需要检查EWOULDBLOCK
  2. 对于Windows系统,请致电errno。如上所述,将发生相同的语义,但ioctlsocket(socket_fd, FIONBIO, (u_long[]){1})代码不会是errno代码(他们将成为errno代码),而他们&#39 ;重新...可能是不同的价值观,我不知道。然而,他们中的许多人都有相似的名字,所以在我的项目中我经常使用类似的东西:

    GetLastError()
  3. 不值得一提

    单独使用非阻塞套接字,如果你设法用一个线程维护几千个连接,在各种需要很少调整的系统上,我都不会感到惊讶。但是,这个模型并不理想,因为您需要一个繁忙的循环来遍历每个套接字,并在每个循环中即时测试它们的事件;例如,当事件到达时,操作系统不会触发您的代码唤醒。

    我们知道,为了将事件发送到应用程序,内核需要处理事件,因此我们可以使用#ifdef _WIN32 #define set_nonblock(fd) (ioctlsocket(fd, FIONBIO, (u_long[]){1}) == 0) #define EAGAIN WSAEWOULDBLOCK #define EWOULDBLOCK WSAEWOULDBLOCK #define EISCONN WSAEISCONN #define EINPROGRESS WSAEINPROGRESS #define EINVAL WSAEINVAL #define EALREADY WSAEALREADY #else #define set_nonblock(fd) (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) != -1) #endif 作为快速修复来给它一些时间。这肯定会使CPU使用率从接近100%下降到10%以下。但是,存在另一种方法,即将多个(阻塞或非阻塞)套接字与非阻塞(或超时中断)功能复用,这样当某些数据可用时,函数将立即返回,或者将等到时间到期才能收到数据。

    sleep(0);显然有很大的好处,但也有缺点;即,这些套件通常仅限于低数量的插座;为了支持大量的套接字,你需要在循环中循环,因为你会发现 64套接字限制(或其他任何东西)快速耗尽。此外,它无法解决select阻塞问题(其中 - connect和~FIONBIO`方法)。

    因此,我不再谈论O_NONBLOCK;我将描述您可以使用的其他选项。具有类似限制的另一个例子是select;我也不会谈论这个。如果你想知道这一点,互联网上有很多关于它的内容......

    请注意,从现在开始的所有内容都非常不可移植(尽管您可能会找到将它们全部包装到公共接口中的方法,例如 curl multi )。

    异步套接字调用将开始连接,然后像非阻塞套接字调用一样立即返回,除了它们还会发出信号或调用您在连接时指定的函数完成。这使操作系统能够控制在事件到达时通知您的代码,而不是等待您的操作系统。应该清楚的是,就优化而言,异步套接字是理想的,但它们不可移植。每个操作系统有多种选择:

    所有这些都有一些共同点,那就是它们在成功或失败时调用一个函数(或引发一个信号,你可以将其转换为对函数的调用)。但是,它们的界面并不那么熟悉。

    通常情况下,我没有为他们编写任何类型的包装,因为我发现在这个答案开头我提到的非阻塞插座现在已经足够了。重要的是我不需要将它移植到每个系统,因为......我太懒了!当有人告诉我它在该系统上运行缓慢时,我才会优化系统。否则,我们最终将自己挖掘成一系列人们甚至不会使用我们的软件......