【发布时间】:2022-12-10 16:19:40
【问题描述】:
我在 C 中使用 TCP 套接字,但还没有真正理解“多远”的数据传输。
我的主要问题是,在我的情况下,服务器有时会向客户端发送一条消息,并希望很快得到答复。如果客户端没有及时应答,服务器将关闭连接。 在阅读 C 中 recv() 函数的联机帮助页时,我发现了 MSG_PEEK 标志,它让我可以在不实际读取数据的情况下查看/窥视流。
但是服务器是否关心我是否从流中读取?
假设服务器将一系列消息“推送”到流中,客户端应该接收它们。 只要客户端不调用 recv() 那些消息就会保留在 Stream 中,对吗? 我知道在接收数据时正在发送 ACK 消息,但是当我调用 recv() 函数时是否发送了 ACK,或者当消息成功到达目的地时是否已经发送了 ACK 并且如果客户端选择(强调可以)可以接收它调用 recv()?
我的希望是欺骗服务器认为消息还没有完全发送,因为客户端还没有调用 recv()。因此,客户端已经可以通过使用 MSG_PEEK 标志评估消息并确保它始终及时答复。 当然我知道我的服务器超时取决于实现。我的问题基本上是,如果 PEEKING 让服务器认为消息还没有到达它的目的地,或者服务器是否甚至不关心以及何时在使用 recv() 时发送 ACK。
我阅读了有关 recv() 的联机帮助页和 TCP 上的 wiki,但无法真正弄清楚 recv() 如何参与该过程。我在 SO 上发现了一些类似的问题,但没有回答我的问题。
【问题讨论】:
-
不,您阅读时不会发送 ACK。
-
你可能想把它想象成好像有二流:您的机器(您机器的操作系统)和服务器之间的 TCP 流,以及您机器的操作系统和您的程序之间的流。当收到 TCP 数据包时,您的操作系统会确认它们并将它们组装到缓冲区中,等待您的程序读取它们。当您的程序读取时,它会耗尽该缓冲区。
-
如果您遇到代码无法及时响应服务器输入的问题,我相信您会想要重新安排程序的体系结构,而不是尝试使用 ACK 来耍花招。特别是,您希望 (a) 您的程序大部分时间都在阻塞
read或recv调用等待输入(这意味着它保证立即响应),或者 (b) 您的程序是事件-driven,这样一来它知道输入可用时,它就会去读取它。 -
如果您花费大量时间进行处理,这就是导致您错过来自服务器的消息的原因,您可能希望切换到多线程架构,这样您就可以让一个线程进行处理,一个线程与服务器通信。
-
现在,我所说的一切都假设您的 C 程序运行在成熟的操作系统下,具有传统的网络堆栈。如果你在做嵌入式编程,事情可能会完全不同。 (特别是,在嵌入式系统中,很可能不是是你这边的中间缓冲区,其中接收到的 TCP 流的某些部分正在组装,等待你的程序读取它。)