【问题标题】:Reusing the same socket connection for multiple requests为多个请求重用相同的套接字连接
【发布时间】:2017-06-07 03:05:20
【问题描述】:

这个问题可能有点离题,但我不知道还能问哪里。我正在阅读此https://github.com/msgpack-rpc/msgpack-rpc/blob/master/spec.md 并看到规范包括能够使用相同的连接发送乱序消息。

我之前做过 TCP 套接字编程的唯一方法是在套接字上同步发送请求,例如,我将打开一个到 127.0.0.1 的套接字,通过该套接字向该服务器发送请求并等待响应。当我收到我发送的请求的响应时,我在响应请求后通过调用客户端上的close() 和服务器上的close() 来关闭该连接。


作为背景,我正在使用 libevent 使用 C++ 进行一个项目,以做与 RPC 系统所做的非常相似的事情,所以我想知道我应该在底层传输系统中使用什么请求响应套接字周期。

在 C++ thrift 中有一个名为 open() 的客户端方法(可能)打开一个连接并保持打开状态,直到您调用 close()。这在抽象出来的系统中如何工作?例如,在我上面包含的那个 messagepack-RPC 链接中。最好的行动方案是什么?如果没有连接,则打开连接,发送请求,当所有先前的请求都得到服务时关闭该连接(在服务器上,当所有待处理的请求都得到响应时,调用close())?或者我们是否必须以某种方式尝试使该连接在超出请求生命周期的一段时间内保持活动状态?服务器和客户端如何知道那个时间段是什么?例如,我们是否应该在套接字上注册一个读取事件处理程序并在recv() 返回0 时关闭连接?

如果这是一个不同系统以不同方式解决的问题,那么有人可以指导我找到一个资源,我可以使用该资源来阅读保持连接活动的可能模式(最好是在事件驱动的系统中)?例如,我读到 HTTP 服务器总是保持连接打开,这是为什么呢?保持每个连接打开不意味着服务器本质上会泄漏内存吗?

对不起,这个看似基本的问题,我以前只做过非常简单的 TCP 套接字编程,所以我可能不知道事情是怎么做的。

【问题讨论】:

  • 这个问题的答案几乎完全取决于您要做什么,以及您的代码和 TCP 连接另一端的代码之间使用的协议。有些数据协议支持持久连接,有些则不支持。也就是说,由于建立和断开 TCP 连接会产生一定的开销,因此保持一个连接打开并为将来的请求重用它通常有一些好处。
  • @JeremyFriesner 以及应用程序通常如何决定如何做到这一点?我觉得发送心跳可能有点矫枉过正,但我​​不知道如何判断这些决定..
  • 我自己的应用程序只是无限期地保持套接字打开(或者直到用户明确指定他想要断开连接),并在每个数据消息的开头包含一个四字节的单词,指示长度以字节为单位的消息,以便接收者在尝试解析消息之前知道它应该读取多少字节。一旦实现并工作,您可以定期发送小/虚拟消息作为心跳,但除非您尝试主动监控连接的健康状况,否则这并不是必需的。
  • @JeremyFriesner 在用户调用close() 时向服务器发送消息是否是个好主意,例如在我谈到的节俭客户端中。所以服务器知道它可以在套接字上调用close()
  • 不用费心发送消息,只需调用close()。无论如何,服务器都不能依赖您发送明确的“我现在要离开”消息,因为在网络中断(或您的客户端程序崩溃,或用户突然拉动)的情况下客户端机器上的插件),您将无法发送一个。因此,当服务器可以(而且必须!)只是看到连接基于 recv() 的返回值关闭时,发送消息是没有意义的。

标签: c++ sockets tcp libevent multiplexing


【解决方案1】:
  1. 在客户端使用连接池。
  2. 客户端中有一个后台线程,该线程会在一段时间后使空闲连接过期。
  3. 编写服务器,使其可以处理每个接受的套接字上的多个请求,即循环读取请求并发送响应,直到对等方关闭连接,或读取请求时发生读取超时,或发生套接字错误。
  4. 不要从任何一方发送关闭消息。关闭套接字就足够了。
  5. 不要使用应用程序 ping 消息来保持连接处于活动状态。如果对等方或中间路由器认为连接过于昂贵以至于在一段时间后终止它们,那么您没有任何业务试图欺骗它。

这就是大多数 HTTP 实现已经工作的方式。注意两端的超时时间来控制每一端的空闲资源使用情况。

【讨论】:

  • 那么即使是 HTTP 服务器也会在超时时关闭它们的套接字?还是他们等到可以向客户端发送关闭标头?
  • 您也说过循环读取请求,直到发生读取超时。如果客户端向服务器发送一个完整的请求并且该服务器响应然后该连接在剩余的将来空闲怎么办?在这种情况下,超时是否也会导致该连接关闭?
  • 1. HTTP 中没有“关闭标头”。这就是为什么我说“这就是大多数 HTTP 实现的工作方式”。 2. 如我所说,服务器将超时读取不存在的第二个请求。这种情况不需要特殊处理。服务器应该超时所有请求。
  • @Curious:只要有资源,服务器就会经常保持连接打开。如果它开始使用过多的内存、文件描述符等,那么它可以制定如何回收这些资源的策略(例如 - 最近最少使用的空闲连接被关闭和回收)。如果请求来得太快太激烈,它也可以开始快速“拒绝”新连接。
  • @Curious TCP 有一个有趣的特性,在默认和设计下,基本协议没有内置的关闭超时。默认情况下,TCP 连接可以“永远”保持打开状态,即使在任意长的时间段内两端都没有AT ALL发送数据。这允许连接到工作中的服务器,关闭笔记本电脑几个小时,然后重新打开它,相同的 TCP 会话仍然可以工作(只要你的 IP 没有改变)。
猜你喜欢
  • 2015-09-19
  • 2012-11-21
  • 2018-11-28
  • 1970-01-01
  • 1970-01-01
  • 2017-03-21
  • 2011-01-18
  • 2021-01-12
  • 2020-11-11
相关资源
最近更新 更多