C - 安全地解析和发送大量无休止的流中的许多字符串

C - Safely parse and send many strings in large endless stream

我对 C 没有多少经验

我有一个连接到几乎无限文本流 (25Mb/s) 的小型 C 程序。

我想用 zeromq 将字符串的每一行作为单独的消息发送。

因此,我将每秒发送数千条消息,在发送每条消息之前,我想操作通过套接字发送的字符串:

假设我开始于:

Quote {0.0.0.0} XXX <1>A<2>B<3>C

我要

XXX Quote <1>A<2>B<3>C

一般来说,我怎样才能安全地执行此操作,以免 运行 发生内存泄漏?我会有这样的事情(举个例子,main 函数实际上是一个具有不同字符的永无止境的循环):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char* parse(const char* input) {

        char* output;
        char* input_copy = strdup(input);
        char* token;
        char* first;
        char* third;
        char* fourth;

        token = strtok(input_copy, " ");
        first = token;

        for (int i = 0; i < 3; i++)
        {
                token = strtok(NULL, " ");
                if (i == 1) third = token;
                if (i == 2) fourth = token;
        }

        asprintf(&output, "%s %s %s", third, first, fourth);
        return output;
        free(output);
}

int main(void)
{
        const char *a = "Quote {0.0.0.0} XXX <1>A<2>B<3>C";
        //SEND_MESSAGE(parse(a));
        return 0;
}

这行得通吗?

像这样更改您的 main

int main(void)
{
    const char *a = "Quote {0.0.0.0} XXX <1>A<2>B<3>C";
    char *buff = parse(a);
    SEND_MESSAGE(buff);
    free(buff);
    return 0;
}

并删除parsereturn后面的free。您还需要为 output:

分配足够的 space
char *output = malloc(1024); //for example

正如对问题的评论所提到的,最好将 output 声明为全局变量(因此将上一行放在 parse 之外),并将 free 声明为全局变量程序的最后(在输入流的字符串循环之外)。这确实使程序更快。

如果您知道(或可以确定)每个 firstsecondthirdfourth 的最大大小是多少,您可以消除内存泄漏的所有可能性,只需为每个内存泄漏使用固定大小的缓冲区。你说你的 25M/sec 文本被分解成 ,所以大概你正在使用 面向行的输入 函数(例如 fgetsgetline) 从流中读取。在这种情况下,您也可以只使用最大行长度 (X4) 来确保您的固定缓冲区足够。

您正在使用 space 作为分隔符标记为 firstsecondthirdfourth,那么为什么不使用 sscanf?如果您想使用 parse 函数,只需将缓冲区作为参数传递即可。

如果您可以确定一个最大值并且您在 space 上标记化,您可以做一些简单的事情:

#include <stdio.h>

#define MAXC 1024

int main(void)
{
    const char *a = "Quote {0.0.0.0} XXX <1>A<2>B<3>C";
    char first[MAXC] = "",
         second[MAXC] = "",
         third[MAXC] = "",
         fourth[MAXC] = "";

    /* read a line from the stream and simply call sscanf */
    if (sscanf (a, " %s %s %s %s", first, second, third, fourth) == 4)
        printf ("%s %s %s\n", third, first, fourth);

    return 0;
}

(printf只是举例,根据需要将结果传给你的zeromq)

例子Use/Output

$ ./bin/staticbuf
XXX Quote <1>A<2>B<3>C

(这会产生极大简化代码的副作用,并且可能还会大大加快代码速度)。

如果您不能自信地确定最大大小,那么您将陷入 malloc/free 的开销(或使用 POSIX getline 并让它处理分配)。