gpt4 book ai didi

c - 如何编写并行下载的代码?

转载 作者:行者123 更新时间:2023-11-30 18:02:49 27 4
gpt4 key购买 nike

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

此外,我一次最多收到5个请求。
但是如何?我曾想过使用fork(),但并不真正了解如何使用。

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



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

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

最佳答案

有一些现成的软件库将提供此功能。我能想到的主要是卷曲。您可以找到curl多库here的简单介绍。

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

为了进行学术研究,并且由于没有“仅链接”的答案就足够了,因此,我将详细说明多路复用套接字的多种可能方式之一。



无阻塞插座

第一种也是当前最可移植的方法是使用非阻塞套接字和/或非阻塞套接字调用,但是实现这一点很重要(尤其是在使用非阻塞套接字调用时,而不是在文件描述符中设置O_NONBLOCK ):有些东西仍然会阻塞。例如,除非将文件描述符设置为非阻止模式,否则您将无法得到connect立即返回,当然,getaddrinfo(以及类似的标准名称解析功能)也会被阻止。

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

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


对于类Unix系统,请调用fcntl(socket_fd, fcntl(socket_fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK)。之后,对readwriteacceptconnect的所有调用将立即返回,而不会延迟。 connect专门为此设置了一些错误代码(在errno中),例如EALREADYEINPROGRESSEISCONNEWOULDBLOCK,您需要检查它们,因为当您启用非阻塞,某些错误返回值实际上是变相的成功返回值;您需要检查errno
对于Windows系统,请调用ioctlsocket(socket_fd, FIONBIO, (u_long[]){1})。除了errno代码不是errno代码(相反,它们将是GetLastError()代码)之外,它们将发生与上述相同的语义,而且...可能是不同的值,我不知道。不知道。但是,其中许多都具有相似的名称,因此在我的项目中,我通常使用类似以下内容的名称:

#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





不值得一提

如果仅使用无阻塞套接字,就可以在各种系统上进行几乎不需要任何调整的情况下,就可以通过一个线程维护数千个连接,这完全不会让您感到惊讶。但是,此模型并不理想,因为您需要一个繁忙的循环来循环每个套接字,并立即对每个循环的事件进行测试。例如,而不是在事件到达时触发代码来唤醒操作系统。

我们知道,为了将事件发送到应用程序,内核需要处理事件,因此我们可以花一些时间使用 sleep(0);作为快速修复。这肯定会导致CPU使用率从近100%下降到10%以下。但是,存在另一种方法,将多个(无阻塞或无阻塞)套接字与无阻塞(或超时中断)功能复用,这样该功能将在某些数据可用时立即返回,或者等待时间到期以进行接收数据。

select显然具有强大的优势,但是也有缺点;也就是说,通常只限于少量的插座。为了支持大量的套接字,您将需要在一个循环中进行循环,因为您会发现64个套接字限制(或其他限制)很快就会用完。另外,它不能解决 connect阻塞问题(而 O_NONBLOCK和〜FIONBIO`方法可以解决)。

因此,我不再谈论 select。我将介绍您可以使用的其他选项。具有类似限制的另一个示例是 poll;我也不会谈论这个。如果您想知道这一点,互联网上有很多关于它的信息。



请注意,从现在开始,所有内容都是不可移植的(尽管您可以找到将它们包装到通用接口中的方法,例如curl multi一样)。



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


epoll对于Linux
kqueue对于FreeBSD(可能还有OS X?)
Some of the WinSock functions,特别是 WSAAsyncSelect


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

通常,我没有为它们写任何包装程序的麻烦,因为我发现我在此答案开头提到的无阻塞套接字已经足够了。重要的是,我不需要将其移植到每个系统,因为……我太懒了!仅当有人向我显示该系统运行缓慢时,我才会为该系统进行优化。否则,我们最终会陷入大量人们甚至可能从未在我们的软件上使用过我们软件的系统中。

关于c - 如何编写并行下载的代码?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8920333/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com