如何在流套接字字节流中找到特定的字符串

时间:2019-02-18 06:42:26

标签: c

我是C语言的新手,在这里遇到了一些麻烦,我试图通过html文件解析并计算文件中p-tag的数量。我正在使用不同大小的块,大小由用户输入。但是,当大小跳到200时,我得到的p标签数量错误。我使用recv函数来接收文件,并且正在使用缓冲区的内容来计数所述p标签。

username

当块大小为200时,它应该返回13个p标签,但返回15个。

1 个答案:

答案 0 :(得分:3)

有几个问题。大概chunk是缓冲区的大小。现在,如果recv成功,它将返回接收到的字节数。您应该使用 this 计数而不是chunk来限制循环。否则,您甚至会为失败的recv操作运行循环,它将计算缓冲区中存在的任何垃圾。

第二个问题当然是<p>标签实际上可能位于2个块的边界上。

第三个问题是,您可能正在越界读取缓冲区-即使buf[i]有效并不意味着buf[i + 2]是有效的。


最简单的,但可能不是最正确的解决方案是在套接字上使用fdopen,然后使用fgetc(),或读取整个主体< / em>放入缓冲区。让我们使用fdopen

FILE *f = fdopen(s, "r+b");
size_t pcount = 0;

int c = 0;
while (c != EOF)
{
    if ((c = fgetc(f)) == '<' 
         && (c = fgetc(f)) == 'p'
         && (c = fgetc(f)) == '>') 
    {
        pcount += 1;
    }
}

在这里,我们将套接字包装到<stdio.h> FILE中; fgetc返回文件中的下一个字符,并且&&短路;最后一个fgetc的返回值也被捕获在c中;如果返回值是EOF,则循环会中断,并且pcount将包含正确的标记计数。

如果您不能使用fdopen,则可以为套接字编写自己的缓冲逻辑,甚至可以创建一个模拟函数,一次调用recv一个字节...


或者您可以使用状态机:

int pstate = 0;

ssize_t count = recv(s, buf, sizeof buf, 0);
// TODO: add error checking...

for (ssize_t i = 0; i < count; i++)
{
    if (buf[i] == '<') {
        pstate = 1;
    }
    else if (pstate == 1 && buf[i] == 'p') {
        pstate = 2;
    }
    else if (pstate == 2 && buf[i] == '>') {
        pcount += 1;
        pstate = 0;
    }
    else {
        // if any other character is found,
        // or any of these characters was in wrong position
        // then reset the state
        pstate = 0;
    }
}

这将在不同的块大小上正常工作,并且不会超出缓冲区的范围。复杂的是,尽管它仍然缺少外部循环,但与fdopen相比,它确实要复杂得多!