- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我最近对多个项目有了想法,这些项目都涉及从文件中读取 IP 地址。由于它们都应该能够处理大量主机,因此我尝试实现多线程或创建套接字池并从中选择()-ing以实现某种形式的并发以获得更好的性能.在很多情况下,从文件中读取似乎是提高性能的瓶颈。按照我的理解,使用 fgets 或类似文件读取文件是一种同步的阻塞操作。因此,即使我成功地实现了一个异步连接到多个主机的客户端,该操作仍然是同步的,因为我一次只能从一个文件中读取一个地址。
/* partially pseudo code */
/* getaddrinfo() stuff here */
while(fgets(ip, sizeof(ip), file) {
FD_ZERO(&readfds);
/* create n sockets here in a for loop */
for (i = 0; i < socket_num; i++) {
if (newfd > fd[i]) newfd = fd[i];
FD_SET(fd[i], &readfds);
}
/* here's where I think I should connect n sockets to n addresses from file
* but I'm only getting one IP at a time from file, so I'm not sure how to connect to
* n addresses at once with fgets
*/
for (j = 0; j < socket_num; j++) {
if ((connect(socket, ai->ai_addr, ai->ai_addrlen)) == -1)
// error
else {
freeaddrinfo(ai);
FD_SET(socket, &master);
fdmax = socket;
if (select(socket+1, &master, NULL, NULL, &tv) == -1);
// error
if ((recvd = read(socket, banner, RECVD)) <= 0)
// error
if (FD_ISSET(socket, &master))
// print success
}
/* clear sets and close sockets and stuff */
}
我已经在评论中指出了我的问题,但只是为了澄清:我不确定如何在从文件读取的多个目标服务器上执行异步 I/O 操作,因为从文件读取条目似乎是严格同步的.我在多线程方面遇到过类似的问题,但成功率略高。
void *function_passed_to_pthread_create(void *opts)
{
while(fgets(ip_addr, sizeof(ip_addr), opts->file) {
/* speak to ip_addr and get response */
}
}
main()
{
/* necessary stuff */
for (i = 0; i < thread_num; i++) {
pthread_create(&tasks, NULL, above_function, opts)
}
for (j = 0; j < thread_num; j++)
/* join threads */
return 0;
}
这似乎可行,但由于多个线程都在处理同一个文件,因此结果并不总是准确的。我想这是因为多个线程可能同时处理文件中的相同地址。
我考虑过将文件中的所有条目加载到数组/内存中,但如果文件特别大,我想这可能会导致内存问题。最重要的是,我不确定这样做是否有意义。
作为最后的说明;如果我正在读取的文件恰好是一个具有大量 IP 的特别大的文件,那么我认为这两种解决方案都无法很好地扩展。不过,使用 C 语言一切皆有可能,所以我想有一些方法可以实现我所希望的。
总结这篇文章;我想找到一种在从文件读取条目时使用异步 I/O 或多线程来提高客户端应用程序性能的方法。
最佳答案
一些人在他们的评论中暗示了一个很好的解决方案,但可能值得更详细地说明。 完整 解决方案包含很多细节并且代码非常复杂,因此我将使用伪代码来解释我的建议。
您在这里遇到的实际上是经典生产者/消费者问题的变体:您有一个生成数据的事物,以及许多试图使用该数据的事物。在您的情况下,它必须是生成该数据的“单一事物”,因为源文件每行的长度是未知的:您不能只向前跳“n”个字节并以某种方式在下一个IP。一次只能有一个参与者将读取指针移向 \n
的下一个未知位置,因此根据定义,您只有一个生产者。
一般有3种攻击方式:
解决方案 A 涉及让每个线程从共享文件缓冲区中拉出更多,并在每次最后一次读取时启动异步(非阻塞)读取阅读完成。要使这个解决方案正确,会遇到一大堆令人头疼的问题,因为它对文件系统和正在执行的工作之间的时间差异非常敏感:如果文件读取速度很慢,所有工作人员都会停止等待文件。如果工作人员速度慢,文件读取器将停止或填满内存以等待他们使用数据。此解决方案可能是绝对 最快的解决方案,但它也是非常难以正确处理大量警告的同步代码。除非您是线程专家(或者非常巧妙地滥用 epoll_wait()
),否则您可能不想走这条路。
解决方案 B 有一个“主”线程,负责读取文件,并用它读取的数据填充某种线程安全队列,每个队列条目有一个 IP 地址(一个字符串)。每个工作线程都尽可能快地使用队列条目,查询远程服务器,然后请求另一个队列条目。这需要一点小心才能正确,但通常比解决方案 A 安全得多,尤其是当您使用其他人的队列实现时。
解决方案 C 非常玄妙,但您不应该立即忽略它,具体取决于您在做什么。该解决方案仅涉及使用类似 Un*x sed
命令(请参阅 Get a range of lines from a file given the start and end line numbers )的东西将您的源文件预先分割成一堆“ block 状”源文件——比如说,20 个。然后,您只需使用 &
并行运行一个非常简单的单线程程序的 20 个副本,每个副本位于文件的不同“切片”上。结合一个小的 shell 脚本来实现自动化,这可能是满足很多需求的“足够好”的解决方案。
让我们仔细看看解决方案 B — 具有线程安全队列的主线程。我要作弊并假设您可以构造一个工作队列实现(如果不能,有 StackOverflow 文章介绍如何使用 pthreads 实现线程安全队列:pthread synchronized blocking queue)。
在伪代码中,这个解决方案是这样的:
main()
{
/* Create a queue. */
queue = create_queue();
/* Kick off the master thread to read the file, and give it the queue. */
master_thread = pthread_create(master, queue);
/* Kick off a bunch of workers with access to the queue. */
for (i = 0; i < 20; i++) {
worker_thread[i] = pthread_create(worker, queue);
}
/* Wait for everybody to finish. */
pthread_join(master_thread);
for (i = 0; i < 20; i++) {
pthread_join(worker_thread[i]);
}
}
void master(queue q)
{
FILE *fp = fopen("ips.txt", "r");
char buffer[BIGGER_THAN_ANY_IP];
/* Inhale the file as fast as we can, and push each line we
read onto the queue. */
while (fgets(fp, buffer) != NULL) {
char *next_ip = strdup(buffer);
enqueue(q, next_ip);
}
/* Add some final messages in the queue to let the workers
know that we're out of data. There are *much* better ways
of notifying them that we're "done", but in this case,
pushing a bunch of NULLs equal to the number of threads is
simple and probably good enough. */
for (i = 0; i < 20; i++) {
enqueue(q, NULL);
}
}
void worker(queue q)
{
char *ip;
/* Inhale messages off the queue as fast as we can until
we get a "NULL", which means that it's time to stop.
The call to dequeue() *must* block if there's nothing
in the queue; the call should only return NULL if the
queue actually had NULL pushed into it. */
while ((ip = dequeue(q)) != NULL) {
/* Insert code to actually do the work here. */
connect_and_send_and_receive_to(ip);
}
}
在实际实现中有很多注意事项和细节(例如:我们如何实现队列、环形缓冲区或链表?如果文本不全是 IP 怎么办?如果字符缓冲区不大怎么办够了吗?多少线程就够了?我们如何处理文件或网络错误?malloc 性能会成为瓶颈吗?如果队列太大怎么办?我们可以更好地重叠网络 I/O 吗?)。
但是,抛开注意事项和细节不谈,我上面提供的伪代码是一个足够好的起点,您可以将其扩展为一个可行的解决方案。
关于c - 从文件中读取异步 I/O,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42384933/
今天我在一个 Java 应用程序中看到了几种不同的加载文件的方法。 文件:/ 文件:// 文件:/// 这三个 URL 开头有什么区别?使用它们的首选方式是什么? 非常感谢 斯特凡 最佳答案 file
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我有一个 javascript 文件,并且在该方法中有一个“测试”方法,我喜欢调用 C# 函数。 c# 函数与 javascript 文件不在同一文件中。 它位于 .cs 文件中。那么我该如何管理 j
需要检查我使用的文件/目录的权限 //filePath = path of file/directory access denied by user ( in windows ) File fil
我在一个目录中有很多 java 文件,我想在我的 Intellij 项目中使用它。但是我不想每次开始一个新项目时都将 java 文件复制到我的项目中。 我知道我可以在 Visual Studio 和
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a software
我有 3 个组件的 Twig 文件: 文件 1: {# content-here #} 文件 2: {{ title-here }} {# content-here #}
我得到了 mod_ldap.c 和 mod_authnz_ldap.c 文件。我需要使用 Linux 命令的 mod_ldap.so 和 mod_authnz_ldap.so 文件。 最佳答案 从 c
我想使用PIE在我的项目中使用 IE7。 但是我不明白的是,我只能在网络服务器上使用 .htc 文件吗? 我可以在没有网络服务器的情况下通过浏览器加载的本地页面中使用它吗? 我在 PIE 的文档中看到
我在 CI 管道中考虑这一点,我应该首先构建和测试我的应用程序,结果应该是一个 docker 镜像。 我想知道使用构建环境在构建服务器上构建然后运行测试是否更常见。也许为此使用构建脚本。最后只需将 j
using namespace std; struct WebSites { string siteName; int rank; string getSiteName() {
我是 Linux 新手,目前正在尝试使用 ginkgo USB-CAN 接口(interface) 的 API 编程功能。为了使用 C++ 对 API 进行编程,他们提供了库文件,其中包含三个带有 .
我刚学C语言,在实现一个程序时遇到了问题将 test.txt 文件作为程序的输入。 test.txt 文件的内容是: 1 30 30 40 50 60 2 40 30 50 60 60 3 30 20
如何连接两个tcpdump文件,使一个流量在文件中出现一个接一个?具体来说,我想“乘以”一个 tcpdump 文件,这样所有的 session 将一个接一个地按顺序重复几次。 最佳答案 mergeca
我有一个名为 input.MP4 的文件,它已损坏。它来自闭路电视摄像机。我什么都试过了,ffmpeg , VLC 转换,没有运气。但是,我使用了 mediainfo和 exiftool并提取以下信息
我想做什么? 我想提取 ISO 文件并编辑其中的文件,然后将其重新打包回 ISO 文件。 (正如你已经读过的) 我为什么要这样做? 我想开始修改 PSP ISO,为此我必须使用游戏资源、 Assets
给定一个 gzip 文件 Z,如果我将其解压缩为 Z',有什么办法可以重新压缩它以恢复完全相同的 gzip 文件 Z?在粗略阅读了 DEFLATE 格式后,我猜不会,因为任何给定的文件都可能在 DEF
我必须从数据库向我的邮件 ID 发送一封带有附件的邮件。 EXEC msdb.dbo.sp_send_dbmail @profile_name = 'Adventure Works Admin
我有一个大的 M4B 文件和一个 CUE 文件。我想将其拆分为多个 M4B 文件,或将其拆分为多个 MP3 文件(以前首选)。 我想在命令行中执行此操作(OS X,但如果需要可以使用 Linux),而
快速提问。我有一个没有实现文件的类的项目。 然后在 AppDelegate 我有: #import "AppDelegate.h" #import "SomeClass.h" @interface A
我是一名优秀的程序员,十分优秀!