【问题标题】:What are best practices of designing and implementing Network Protocols?设计和实施网络协议的最佳实践是什么?
【发布时间】:2010-10-20 16:42:17
【问题描述】:

我第一次尝试通过 TCP/IP 实现一些网络协议。我设计了一个,但我不确定它是否有效。

设计

所以这是我的想法:在客户端打开与服务器的 TCP/IP 连接后,每次它想要发出请求时,首先它发送请求的大小,然后是一些分隔符(新行或空格),然后是实际的请求(在 HTTP 中使用相同的主体,我认为在大多数情况下都会使用此想法)。

例如,如果客户端要发送 GET ASD,它实际上会发送 7 个 GET ASD(假设空格是分隔符)。

对于服务器端,每个客户端服务器都有缓冲区,用于保存传入的请求。每当它从客户端获得一些新的字符块时,服务器会将其附加到相应的客户端缓冲区。之后,服务器将尝试获取请求的内容长度(在此示例中为 7)并检查缓冲区的其余长度是否大于或等于它。如果是,服务器将获取请求的实际内容,处理并将其从缓冲区中删除。

实施

这都是关于协议设计的,现在是关于实际实现的一些注释:我认为这里的主要问题是有效地实现和管理缓冲区。

我认为大小为 2 * MAX_SIZE_OF_ONE_REQUEST 的缓冲区足以为一个客户端提供服务,因为服务器接收到的块可以同时包含第一个请求的结尾和第二个请求的开头。这是我的假设,如果我错了,我们需要更多或更少的空间,请告诉我原因。

我认为有两种方法可以将请求存储在缓冲区中,直到它们被服务:

  1. 每当服务器接收到新的字符块时,服务器会将其附加到缓冲区的右侧。一旦缓冲区包含完整的请求,服务器将处理它并将缓冲区的所有其余部分移到缓冲区空间的开头。

  2. 一些循环缓冲区在处理请求后开始时不移动缓冲区。

这是我对使用异步 I/O 实现缓冲区的想法(服务器将使用 epoll/kqueue/select 来接收来自客户端的请求)。我认为如果服务器不使用异步 I/O 与客户端通信,那么实现缓冲区会简单得多。

此外,我还没有决定服务器在收到格式错误的请求时应该如何表现。是否应该关闭与客户端的连接?

也许我写了很多,但我真的对这个话题很感兴趣,想尽可能多地学习。我想有很多人和我一样,所以任何关于这个主题的现实世界问题以及解决这些问题的最佳实践都会非常有帮助。1。

【问题讨论】:

  • 在进行任何类型的设计之前分析 API 的要求很重要。如果你能详细说明这些,可能会更容易。
  • Redis 给了我很大的启发,出于学习的目的,我开始了一个小项目 Kivi (K/V Store):github.com/giolekva/kivi 所以会有像 GET、SET、DEL、INCR 这样的命令, ... 就像在 Redis 中一样。
  • (评论是因为我对你的问题没有完整的答案):我发现最好防止出现格式错误的请求。在这种情况下,长度和请求可能不一致,所以我会取消长度。相反,您可以使用一些特殊的终止符('\0' 在许多情况下都很好用)。当然,客户端仍然有可能发送一个永无止境的字符串以使服务器过载,但至少如果长度错误,您不会等待更多字节。
  • '在 HTTP 中使用相同的原理。'不,不是。 HTTP 是基于行的协议。它可能包含也可能不包含长度标头。您可能比研究 Internet 协议家族(FTP、HTTP、SMTP 等)真正如何工作更糟糕。

标签: networking tcp network-programming computer-science network-protocols


【解决方案1】:

您需要人类可读的协议吗?如果不是,那么我建议使用二进制,从 x 字节的命令长度开始,然后按照您认为合适的方式形成消息的其余部分;当然,如果您愿意,消息的其余部分可以是文本......恕我直言,这在服务器上更容易处理,因为您不需要扫描所有输入字节来确定消息何时结束。

由于您知道确定消息长度所需的(固定)字节数,因此您可以忽略所有消息,直到它们达到那么长为止。您(可能)具有合理的最大消息大小,因此可以根据可以容纳所有消息的缓冲区工作。这意味着您可以将读取累积到单个缓冲区中,直到您获得完整的消息,无需复制,无需移动。一旦你有一个完整的消息,你可以传递这个缓冲区进行处理并开始读入一个新的。引用计数缓冲区,当您使用完它们时,它们可以返回到池中。

为了防止拒绝服务攻击,您应该对读取数据设置超时。 x 中没有完整的消息,您断开连接。

格式错误的消息,您断开连接。恕我直言Postel 有很多要回答的问题;恕我直言,当你迂腐地认为人们把事情做对并且接受不多时,恕我直言协议会更好......

消息大小超过您允许的范围,您断开连接。

我讨论了关于长度前缀和基于行(序列终止)协议的 TCP 消息帧问题 herehere,尽管讨论集中在我的免费可插拔服务器平台 WASP 所以它可能会也可能会对你没用。

说实话,这很容易。复杂的部分是设计允许客户端和服务器有效地就问题空间进行对话的实际协议......但是,一旦你进入更复杂的部分,弄错这一点可能会导致有趣的问题......

【讨论】:

    【解决方案2】:

    首先,我会检查 RFC 和 ITU.T 规范,以了解可以执行您想要执行的操作的协议。如果找不到,至少可以了解其他协议是如何设计的,并了解其背后的一些基本原理。

    查看 XDR 或 BER (ASN.1) 以了解数据的二进制编码。有一些库可以处理字节序和对齐混乱。例如,将每个数据包包装在 XDR opaque 中可以让您更有效地设计服务器(1 个 TCP 前端模块,它将未处理的 opaque 发送到适当的处理程序,而无需知道每个数据包的含义)。

    正如 Len Holgate 所提到的,一定要指定在特殊情况下应该发生什么(格式错误的数据包,无响应)或者是否应该有任何保持活动的数据包?如果有,多久一次?是否应该进行一些客户端-服务器协商。

    哦,别忘了在 hello 数据包中包含协议版本。使用“我的客户端应用程序说我不支持协议的第 2 版”获得问题票比“某些客户端工作正常,但是当我尝试接收数据集时得到的只是随机数!”更好。

    【讨论】:

    • +1 表示协议版本,+2 如果可以查看其他人的规格...
    猜你喜欢
    • 1970-01-01
    • 2011-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-08
    • 2019-02-18
    相关资源
    最近更新 更多