当前位置:编程学习 > JAVA >>

这么短的代码真的没有人能解决吗?写入Socket出现TCP Zero Window!

这段代码问过很多人了,都不太清楚怎么回事,在Stackoverflow上问过,还是没有解决,这里高手多,来这里问一下,请各位大牛指点一二!

代码很短,简单说一下,就是每隔几秒向网站发送一个HTTP报文,发送的形式就是直接向80端口写入HTTP报文,然后读取信息(这里我对读取的信息没有做任何处理,因为暂时不需要处理,读取一下只是为了防止HTTP连接关闭),用Wireshark抓包,可以看到结果:第一次成功,第二次成功,第五次以后TCP Window就变成0了,通过截图可以发现,实际上TCP Windows处于不停变小的状态,我猜服务器端没有对TCP报文做出确认的响应?但是相同的请求报文,用Chrome甚至Burp Repeater每隔几秒发送都没有问题,这是为什么?

代码如下:
package MAIN_PACKAGE;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.net.UnknownHostException;

public class pediy {

public static void main(String[] args) throws IOException {

URL url = new URL("http://www.baidu.com");
String request = "GET / HTTP/1.1\r\nHost: www.baidu.com\r\nProxy-Connection: keep-alive\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nUser-Agent: Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.56 Safari/537.17 CoolNovo/2.0.6.12\r\nAccept-Encoding: gzip,deflate,sdch\r\nAccept-Language: zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4\r\nAccept-Charset: gb18030,utf-8;q=0.7,*;q=0.3\r\n";
Socket socket = null;
PrintWriter os = null;
BufferedReader is = null;
InputStreamReader isr = null;

while(true) {

socket = new Socket(url.getHost(), 80);
os = new PrintWriter(socket.getOutputStream());
isr = new InputStreamReader(socket.getInputStream());
is=new BufferedReader(isr);

try {
while (true) {

os.println(request);
os.flush();

                                        //读取返回信息
while(is.read() != 0);

System.out.println("Finished");

Thread.sleep(1000*10);
}

} catch (Exception e) {
System.out.println("Error" + e);
} finally {
CloseAll(socket, os, is, isr);
}
}
}

private static void CloseAll(Socket socket, PrintWriter os, BufferedReader is, InputStreamReader isr) throws IOException {
if(socket != null) socket.close();
if(os != null) os.close();
if(is != null) is.close();
if(isr != null) isr.close();
}
}


抓包:
socket tcp Wireshark  window --------------------编程问答-------------------- 不会呀,刚看了一点io和线程。 --------------------编程问答--------------------  while(is.read() != 0);这句有啥用啊? --------------------编程问答--------------------
引用 2 楼 liuyunsihuo 的回复:
while(is.read() != 0);这句有啥用啊?


读取信息啊,不读的话可能TCP窗口都不会移动,HTTP有可能关闭,实际上我不需要对返回的信息进行处理,所以就循环读取响应了,实际发现去掉好像影响也不大,反正加不加这句结果都是Zero Window --------------------编程问答-------------------- What does TCP Zero Window mean?

Zero Window is something to investigate.

TCP Zero Window is when the Window size in a machine remains at zero for a specified amount of time.

This means that a client is not able to receive further information at the moment, and the TCP transmission is halted until it can process the information in its receive buffer.

TCP Window size is the amount of information that a machine can receive during a TCP session and still be able to process the data. Think if it like a TCP receive buffer. When a machine initiates a TCP connection to a server, it will let the server know how much data it can receive by the Window Size.

In many Windows machines, this value is around 64512 bytes. As the TCP session is initiated and the server begins sending data, the client will decrement it's Window Size as this buffer fills. At the same time, the client is processing the data in the buffer, and is emptying it, making room for more data. Through TCP ACK frames, the client informs the server of how much room is in this buffer. If the TCP Window Size goes down to 0, the client will not be able to receive any more data until it processes and opens the buffer up again. In this case, Protocol Expert will alert a "Zero Window" in Expert View.

Troubleshooting a Zero Window For one reason or another, the machine alerting the Zero Window will not receive any more data from the host. It could be that the machine is running too many processes at that moment, and its processor is maxed. Or it could be that there is an error in the TCP receiver, like a Windows registry misconfiguration. Try to determine what the client was doing when the TCP Zero Window happened. 


找到这么篇文章,猜测原因可能是你不停的发送请求,服务器不停响应而你又不处理服务器响应的数据,导致缓冲区被占满无法再接受更多的服务器数据。

浏览器模拟可以成功估计是浏览器每次都是处理了响应数据的。


试着处理一下响应数据。

我下个抓包工具试验下看看先 --------------------编程问答-------------------- 好吧实验了下用你的代码每秒发送一个请求几秒内就会出现tcp window zero的错误
将每次服务器响应的信息读取后,这个错误就消失了。

把while(is.read() != 0);改成 while(is.readLine() != null);就好了


原因可能就是我说的那样了,服务器响应了太多信息而代码里又不做相应处理所以将tcp缓冲区给占满了。 --------------------编程问答--------------------
引用 5 楼 x19881216 的回复:
好吧实验了下用你的代码每秒发送一个请求几秒内就会出现tcp window zero的错误
将每次服务器响应的信息读取后,这个错误就消失了。

把while(is.read() != 0);改成 while(is.readLine() != null);就好了


原因可能就是我说的那样了,服务器响应了太多信息而代码里又不做相应处理所以将tcp缓冲区给占满了。
……


谢谢你的热心,不过你确定is.readLine() != null这句话没有问题?我使用这句话的时候10次有5次都有问题,很多时候就一直循环,根本无法出现输出“Finished”的情况,我怀疑这句话是否真的有效,用is.read() != 0的时候就很好,GET一次,Finished就输出一次,换了readLine后,根本就无法GET多次 --------------------编程问答-------------------- is.read() != 0一般只读取了几个字节就完了,is.readLine() != null是按行读取,如果一直循环一般不是网速慢就是内容大你可以把读取的内容打印出来看看。

String tmp = null;
while((tmp=is.readLine())!=null){
  System.out.print(tmp);
}

不管你用什么方式只要保证Inputstream里面的内容被完全读取出来就可以了。 --------------------编程问答-------------------- --------------------编程问答-------------------- public int read()
         throws IOException
读取单个字符。
覆盖:
类 Reader 中的 read
返回:
作为一个整数(其范围从 0 到 65535 ( 0x00-0xffff))读入的字符,如果已到达流末尾,则返回 -1
抛出:
IOException - 如果发生 I/O 错误 --------------------编程问答--------------------
引用 9 楼 lb85858585 的回复:
public int read()
         throws IOException
读取单个字符。
覆盖:
类 Reader 中的 read
返回:
作为一个整数(其范围从 0 到 65535 ( 0x00-0xffff))读入的字符,如果已到达流末尾,则返回 -1
抛出:
IOException - 如果发生 I/O 错误


改掉了,while(is.read() != -1);,还是不行,Eclipse里面一直显示Finished,但是Wireshark里面只抓到两个请求包 --------------------编程问答--------------------
引用 7 楼 x19881216 的回复:
is.read() != 0一般只读取了几个字节就完了,is.readLine() != null是按行读取,如果一直循环一般不是网速慢就是内容大你可以把读取的内容打印出来看看。

String tmp = null;
while((tmp=is.readLine())!=null){
  System.out.print(tmp);
}

不管你用什么方式……


改成while(is.read() != -1);了,还是不行,readLine也不行,一般是请求了两三个后就没反应了,你也试一下,可能是HTML中国的报文体被gzip编码了,\r\n这类东西都变成别的东西了,缓冲区太大导致失败
补充:Java ,  Web 开发
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,