0

我从套接字 A 接收并即时将其写入套接字 B(就像代理服务器可能一样)。我想检查并可能修改通过的数据。我的问题是如何处理边界情况,即我正在搜索的正则表达式将在两个连续的套接字 A 读取和套接字 B 写入迭代之间匹配。

char buffer[4096]
int socket_A, socket_B

/* Setting up the connection goes here */

for(;;) {

    recv(socket_A, buffer, 4096, 0);

    /* Inspect, and possibly modify buffer */

    send(socket_B, buffer, 4096, 0);

    /* Oops, the matches I was looking for were at the end of buffer,
     * and will be at the beginning of buffer next iteration :( */

}
4

6 回答 6

1

您需要了解和/或说出您的正则表达式。

根据正则表达式,您可能需要比现在缓冲更多的缓冲。

最坏的情况可能是一个正则表达式,它说“找到所有东西,从开始直到第一次出现‘狗’这个词,然后用其他东西替换它”:如果你有这样的正则表达式,那么你需要缓冲(不转发)从开始到第一次出现“狗”这个词的所有内容:这可能永远不会发生,即可能是无限量的缓冲。

于 2009-05-25T19:21:19.303 回答
1

我的建议:有两个缓冲区,并在它们之间轮换:

  1. 接收缓冲区 1
  2. 接收缓冲区 2
  3. 过程。
  4. 发送缓冲区 1
  5. 接收缓冲区 1
  6. 处理,但在缓冲区 1 之前使用缓冲区 2。
  7. 发送缓冲区 2
  8. 转到 2。

或类似的东西?

于 2009-05-25T18:50:40.117 回答
1

假设您知道可能的正则表达式匹配的最大长度 M(或者可以使用任意值 - 或者只使用整个缓冲区),您可以通过不传递完整缓冲区但保留 M-1 个字节来处理它。在下一次迭代中,将新接收到的数据放在 M-1 个字节的末尾并应用正则表达式。

如果您知道传输数据的格式(例如 http),您应该能够解析内容以了解何时到达通信结束,并且应该发送您可能已缓存的尾随字节。如果您不知道格式,那么您需要在 recv 中实现超时,这样您就不会在通信结束时等待太久。太长是你必须自己决定的事情,

于 2009-05-25T18:52:33.280 回答
1

从这个意义上说,您正在谈论(以及所有意义上的 TCP)套接字是流。根据您的问题,您在数据中有一些结构。因此,您必须执行类似于以下的操作:

  1. 缓冲(保持)传入数据,直到达到边界。边界可能是行尾、记录尾或您知道正则表达式将匹配的任何其他方式。
  2. 当“记录”准备好时,处理它并将结果放在输出缓冲区中。
  3. 写入输出缓冲区中累积的任何内容。

这可以处理大多数情况。如果您遇到真正没有“记录”的罕见情况之一,那么您必须构建某种状态机(DFA)。我的意思是你必须能够积累数据,直到a)它不可能匹配你的正则表达式,或者b)它是一个完整的匹配。

编辑: 如果您匹配固定字符串而不是真正的正则表达式,那么您应该能够使用Boyer-Moore算法,该算法实际上可以在亚线性时间内运行(通过跳过字符)。如果你做对了,当你移动输入时,你可以将以前看到的数据扔到输出缓冲区,从而显着减少延迟并提高吞吐量。

于 2009-05-25T18:53:27.927 回答
0

一种替代方法是对poll(2)非阻塞套接字使用 -like 策略。在读取事件时,从套接字获取缓冲区,将其推送到传入队列,调用将缓冲区组装成流的词法分析器/解析器/匹配器,然后将块推送到输出队列。在写入事件中,从输出队列中取出一个块(如果有),并将其写入套接字。这听起来有点复杂,但一旦你习惯了反向控制模型,它就不是真的了。

于 2009-05-25T19:35:18.480 回答
0

基本上,您的代码的问题在于,recv/send 循环在比您的修改更低的网络层上运行。你如何解决这个问题取决于你所做的修改,但它可能涉及缓冲数据,直到可以进行所有本地修改。

编辑:我不知道任何可以过滤这样的流的正则表达式库。这将有多难取决于您的正则表达式及其过滤的协议。

于 2009-05-25T18:52:53.950 回答