代码改变世界

记一次netty http server给客户端返回reset包排除

2019-10-11 21:58  Loull  阅读(1522)  评论(1编辑  收藏  举报

类似文章:解决用netty去做web服务时,post长度过大的问题

现象:当客户端给server发送的请求体较大时,服务直接给客户端返回reset包。

tcpdump:

 

 

 

 

 

 应用还没有完全收上去,就close这个fd,造成发送reset包。

 

https://github.com/torvalds/linux/blob/master/net/ipv4/tcp.c#L2384

 

 

 

 

netstat -s |grep "connections reset due to early user close" 这个计数器一直在增加

 

因为返回的 RST 包有窗口大小,所以这是主动调用的 tcp_send_active_reset, 代码里有 bug,读缓冲里有数据没读完直接 close 了。

 

程序里判断如果msg不可读,就把channel close掉。而当请求体过大时,netty会把msg设置为chunked,而chunked的msg也是不可读的,结果就导致了问题:缓冲区还有数据,但不可读,程序就把channel close了,操作系统这时会发送reset包,导致客户端收到reset包。

netty3的HttpRequestDecoder注释:

    /**
     * Creates a new instance with the default
     * {@code maxInitialLineLength (4096}}, {@code maxHeaderSize (8192)}, and
     * {@code maxChunkSize (8192)}.
     */
    public HttpRequestDecoder() {
    }

org.jboss.netty.handler.codec.http.HttpMessageDecoder#decode方法里:

            case READ_VARIABLE_LENGTH_CONTENT:
                if (buffer.readableBytes() > maxChunkSize || HttpHeaders.is100ContinueExpected(message)) {
                    // Generate HttpMessage first.  HttpChunks will follow.
                    checkpoint(State.READ_VARIABLE_LENGTH_CONTENT_AS_CHUNKS);
                    message.setChunked(true);
                    return message;
                }
                break;

 

 

修复方式,在netty handler pipeline里添加 HttpChunkAggregator