【发布时间】:2010-10-20 16:42:17
【问题描述】:
我第一次尝试通过 TCP/IP 实现一些网络协议。我设计了一个,但我不确定它是否有效。
设计
所以这是我的想法:在客户端打开与服务器的 TCP/IP 连接后,每次它想要发出请求时,首先它发送请求的大小,然后是一些分隔符(新行或空格),然后是实际的请求(在 HTTP 中使用相同的主体,我认为在大多数情况下都会使用此想法)。
例如,如果客户端要发送 GET ASD,它实际上会发送 7 个 GET ASD(假设空格是分隔符)。
对于服务器端,每个客户端服务器都有缓冲区,用于保存传入的请求。每当它从客户端获得一些新的字符块时,服务器会将其附加到相应的客户端缓冲区。之后,服务器将尝试获取请求的内容长度(在此示例中为 7)并检查缓冲区的其余长度是否大于或等于它。如果是,服务器将获取请求的实际内容,处理并将其从缓冲区中删除。
实施
这都是关于协议设计的,现在是关于实际实现的一些注释:我认为这里的主要问题是有效地实现和管理缓冲区。
我认为大小为 2 * MAX_SIZE_OF_ONE_REQUEST 的缓冲区足以为一个客户端提供服务,因为服务器接收到的块可以同时包含第一个请求的结尾和第二个请求的开头。这是我的假设,如果我错了,我们需要更多或更少的空间,请告诉我原因。
我认为有两种方法可以将请求存储在缓冲区中,直到它们被服务:
每当服务器接收到新的字符块时,服务器会将其附加到缓冲区的右侧。一旦缓冲区包含完整的请求,服务器将处理它并将缓冲区的所有其余部分移到缓冲区空间的开头。
一些循环缓冲区在处理请求后开始时不移动缓冲区。
这是我对使用异步 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