1

我正在编写 http 解析器并具有这些功能

int parse_useragent(char* buf, int length){
    buf[length] = '\0';
    if(strstr(buf, "MSIE") != NULL){
        return 1;
    }else if(strstr(buf, "Firefox") != NULL){
        return 2;
    }
    return DEFAULT_USERAGENT;
}

void parse_headers(unsigned char* buf, http_record_t * http){
    char * position = (char*)buf;
    char referer[] = "Referer";
    char useragent[] = "User-Agent";
    ...
    int length = getlinelength(position); // returns length of line
    while(length != 1){ // position points to start of line every iteration of cycle
        if(strncmp(position, useragent, sizeof(useragent)-1) == 0){
            http->useragent = parse_useragent(position, length);
            fprintf(stderr,"parsing useragent \n");
        }else if(strncmp(position, referer, sizeof(referer)-1) == 0){
            fprintf(stderr,"parsing referer \n");
            char * tmp = malloc(REFERER_LENGHT * sizeof(char));
            parse_referer(tmp,position, length);
            strncpy(http->referer,tmp, REFERER_LENGHT * sizeof(char) - 1);
        }else if(...

        position += length + 1;
        length = getlinelength(position);
    }
    return;
}

buf指向http头的开始。

parse_useragent对每个标题都有类似的功能,我真的需要优化它们。数据包长度通常小于 1000,行长很少超过 100 值。对这么短的字符串进行优化会有什么明显的效果吗?

我知道其中一些算法需要不同的解析方法,然后逐行解析。在这些特定条件下选择哪种方式?

感谢帮助!

4

2 回答 2

1

如果您不介意将字符串硬编码到代码中,我认为 lex 将是完成此类任务的最快工具。因为它在源代码中显式地构建了一个有限状态自动机。

这是执行此任务的示例 lex 代码:

%option noyywrap
%{
enum Type{
    TFIREFOX = 0, TMSIE = 1
};
enum Type global_variable; /* the variable to store the parsing result */
%}

%%
FIREFOX {global_variable = TFIREFOX; yyterminate();}
MSIE {global_variable = TMSIE; yyterminate();}
. {}
%%

int lex_strstr(char *buf, int n)
{
    global_variable = -1;
    YY_BUFFER_STATE bs = yy_scan_buffer(buf, n);
    yy_switch_to_buffer(bs);
    yylex();
    return global_variable;
}

将其存储在某个文件中,resulte.l并使用 flex 对其进行编译以获取 ac 头文件:

flex -o head.h result.l

这里有一个例子来展示它是如何工作的:

#include "head.h"
int main()
{
    {
        char buf[] = "this is a test MSIE string\0\0";
        printf("%d\n", lex_strstr(buf, (sizeof buf)));
    }
    {
        char buf[] = "this is a test FIREFOX string\0\0";
        printf("%d\n", lex_strstr(buf, (sizeof buf)));
    }
    {
        char buf[] = "this is a test MSIEFIREFOX string\0\0";
        printf("%d\n", lex_strstr(buf, (sizeof buf)));
    }
    {
        char buf[] = "this is a test MIEFIEFOXdfa\0\0";
        printf("%d\n", lex_strstr(buf, (sizeof buf)));
    }
}

结果:

1
0
1
-1
于 2012-09-26T11:46:49.473 回答
0

将您的字符串转换为长度前缀。

很多时间都浪费在寻找 C 字符串中的终止 nul 字符上,而带有长度前缀的字符串消除了这种浪费,同时增加了它自己的一点点开销。

在野外有一个库是 BSD 或 MIT 许可的(阅读:任何人都可以免费使用),它非常优化并且错误数量非常少。但是,对于我的生活,我想不出 lib 的名称。可能是Safestr 。在此处查找有关查找 Safestr 的提示,或在此处查找是否会为您加载页面。

于 2012-09-26T10:32:03.023 回答