Java 什么是 TCP 窗口更新?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1466307/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 12:35:38  来源:igfitidea点击:

What is a TCP window update?

javanetworkingsocketstcpwireshark

提问by phpscriptcoder

I'm making my own custom server software for a game in Java (the game and original server software were written with Java). There isn't any protocol documentation available, so I am having to read the packets with Wireshark.

我正在为 Java 游戏制作自己的自定义服务器软件(游戏和原始服务器软件是用 Java 编写的)。没有任何可用的协议文档,因此我必须使用 Wireshark 读取数据包。

While a client is connecting the server sends it the level file in Gzip format. At about 94 packets into sending the level, my server crashes the client with an ArrayIndexOutOfBoundsException. According to the capture file from the original server, it sends a TCP Window Update at about that point. What is a TCP Window Update, and how would I send one using a SocketChannel?

当客户端连接服务器时,它会以 Gzip 格式向其发送关卡文件。在发送级别大约 94 个数据包时,我的服务器使用 ArrayIndexOutOfBoundsException 使客户端崩溃。根据来自原始服务器的捕获文件,它大约在那个时候发送 TCP 窗口更新。什么是 TCP 窗口更新,我将如何使用 SocketChannel 发送一个?

采纳答案by ZZ Coder

TCP windows are used for flow control between the peers on a connection. With each ACK packet, a host will send a "window size" field. This field says how many bytes of data that host can receive before it's full. The sender is not supposed to send more than that amount of data.

TCP 窗口用于连接上的对等点之间的流量控制。对于每个 ACK​​ 数据包,主机将发送一个“窗口大小”字段。该字段表示主机在数据满之前可以接收多少字节的数据。发送方不应发送超过该数量的数据。

The window might get full if the client isn't receiving data fast enough. In other words, the TCP buffers can fill up while the application is off doing something other than reading from its socket. When that happens, the client would send an ACK packet with the "window full" bit set. At that point, the server is supposed to stop sending data. Any packets sent to a machine with a full window will notbe acknowledged. (This will cause a badly behaved sender to retransmit. A well-behaved sender will just buffer the outgoing data. If the buffer on the sending side fills up too, then the sending app will block when it tries to write more data to the socket!)

如果客户端接收数据的速度不够快,窗口可能会变满。换句话说,TCP 缓冲区可能会在应用程序停止执行除从其套接字读取之外的其他操作时填满。当这种情况发生时,客户端将发送一个带有“窗口已满”位设置的 ACK 数据包。此时,服务器应该停止发送数据。发送到具有完整窗口的机器的任何数据包都不会被确认。(这将导致行为不端的发送方重新传输。行为良好的发送方只会缓冲传出的数据。如果发送方的缓冲区也填满了,那么发送应用程序将在尝试将更多数据写入套接字时阻塞!)

This is a TCP stall. It can happen for a lot of reasons, but ultimately it just means the sender is transmitting faster than the receiver is reading.

这是一个 TCP 停顿。发生这种情况的原因有很多,但最终它只是意味着发送方的传输速度比接收方的读取速度快。

Once the app on the receiving end gets back around to reading from the socket, it will drain some of the buffered data, which frees up some space. The receiver will then send a "window update" packet to tell the sender how much data it can transmit. The sender starts transmitting its buffered data and traffic should flow normally.

一旦接收端的应用程序重新开始从套接字读取,它就会耗尽一些缓冲的数据,从而释放一些空间。然后接收方将发送一个“窗口更新”数据包,告诉发送方它可以传输多少数据。发送方开始传输其缓冲数据,流量应该正常流动。

Of course, you can get repeated stalls if the receiver is consistently slow.

当然,如果接收器一直很慢,您可能会重复停顿。

I've worded this as if the sender and receiver are different, but in reality, both peers are exchanging window updates with every ACK packet, and either side can have its window fill up.

我的措辞好像发送方和接收方不同,但实际上,两个对等方都在与每个 ACK​​ 数据包交换窗口更新,并且任何一方都可以填满其窗口。

The overall message is that you don't need to send window update packets directly. It would actually be a bad idea to spoof one up.

总体消息是您不需要直接发送窗口更新数据包。欺骗一个人实际上是一个坏主意。

Regarding the exception you're seeing... it's not likely to be either caused or prevented by the window update packet. However, if the client is not reading fast enough, you might be losing data. In your server, you should check the return value from your Socket.write() calls. It could be less than the number of bytes you're trying to write. This happens if the sender's transmit buffer gets full, which can happen during a TCP stall. You might be losing bytes.

关于您看到的异常......它不太可能由窗口更新数据包引起或阻止。但是,如果客户端读取速度不够快,您可能会丢失数据。在您的服务器中,您应该检查 Socket.write() 调用的返回值。它可能小于您尝试写入的字节数。如果发送方的传输缓冲区已满,就会发生这种情况,这可能发生在 TCP 停顿期间。您可能正在丢失字节。

For example, if you're trying to write 8192 bytes with each call to write, but one of the calls returns 5691, then you need to send the remaining 2501 bytes on the next call. Otherwise, the client won't see the remainder of that 8K block and your file will be shorter on the client side than on the server side.

例如,如果您尝试在每次 write 调用时写入 8192 个字节,但其中一个调用返回 5691,那么您需要在下一次调用时发送剩余的 2501 个字节。否则,客户端将看不到该 8K 块的其余部分,并且您的文件在客户端将比在服务器端更短。

回答by Aaron Digulla

This happens really deep in the TCP/IP stack; in your application (server and client) you don't have to worry about TCP windows. The error must be something else.

这发生在 TCP/IP 堆栈的深处;在您的应用程序(服务器和客户端)中,您不必担心 TCP 窗口。错误一定是别的东西。

回答by Hymanson

You can dive into this web site http://www.tcpipguide.com/free/index.htmfor lots of information on TCP/IP.

您可以进入这个网站http://www.tcpipguide.com/free/index.htm获取大量关于 TCP/IP 的信息。

回答by Yishai

A TCP Window Update has to do with communicating the available buffer size between the sender and the receiver. An ArrayIndexOutOfBoundsException is not the likely cause of this. Most likely is that the code is expecting some kind of data that it is not getting (quite possibly well before this point that it is only now referencing). Without seeing the code and the stack trace, it is really hard to say anything more.

TCP 窗口更新与发送方和接收方之间的可用缓冲区大小通信有关。ArrayIndexOutOfBoundsException 不是造成这种情况的可能原因。最有可能的是,代码期望得到某种它没有得到的数据(很可能在这之前它只是现在才引用)。没有看到代码和堆栈跟踪,真的很难再说什么。

回答by nik

Do you get any detailswith the exception?

你得到任何细节例外

It is not likely related to the TCP Window Update packet
(have you seen it repeat exactly for multiple instances?)

它不太可能与 TCP Window Update 数据包有关
(您是否看到它在多个实例中完全重复?)

More likely related to your processing code that works on the received data.

更有可能与处理接收数据的处理代码有关。

回答by ZZ Coder

This is normally just a trigger, not the cause of your problem.

这通常只是一个触发器,而不是问题的原因。

For example, if you use NIO selector, a window update may trigger the wake up of a writing channel. That in turn triggers the faulty logic in your code.

例如,如果您使用 NIO 选择器,则窗口更新可能会触发写入通道的唤醒。这反过来会触发代码中的错误逻辑。

Get a stacktrace and it will show you the root cause.

获取堆栈跟踪,它将向您显示根本原因。

回答by SimonZC

TCP WindowUpdate - This indicates that the segment was a pure WindowUpdate segment. A WindowUpdate occurs when the application on the receiving side has consumed already received data from the RX buffer causing the TCP layer to send a WindowUpdate to the other side to indicate that there is now more space available in the buffer. Typically seen after a TCP ZeroWindow condition has occurred. Once the application on the receiver retrieves data from the TCP buffer, thereby freeing up space, the receiver should notify the sender that the TCP ZeroWindow condition no longer exists by sending a TCP WindowUpdate that advertises the current window size.

TCP WindowUpdate - 这表明该段是纯 WindowUpdate 段。当接收端的应用程序消耗了已经从 RX 缓冲区接收到的数据,导致 TCP 层向另一端发送 WindowUpdate 以指示缓冲区中现在有更多可用空间时,就会发生 WindowUpdate。通常在 TCP ZeroWindow 条件发生后出现。一旦接收器上的应用程序从 TCP 缓冲区检索数据,从而释放空间,接收器应通过发送通告当前窗口大小的 TCP WindowUpdate 通知发送器 TCP ZeroWindow 条件不再存在。

https://wiki.wireshark.org/TCP_Analyze_Sequence_Numbers

https://wiki.wireshark.org/TCP_Analyze_Sequence_Numbers