后端技术总结

  • 首页
  • github
  • About Me
  1. 首页
  2. Golang
  3. 正文

Golang之HTTP EOF/connection reset by peer详解

2019年6月10日 7062点热度 14人点赞 0条评论
内容纲要

背景

使用net/http同时发起多个简单请求时,偶尔会出现EOF或connect: connection reset by peer的情况。明明就是一个很简单的例子,为何会出现这种情况呢?

举例

这里我为了省事,直接套用网上其他人的客户端的例子:

req, err := http.NewRequest(method, url, body)
if err !=nil{

    return nil, err

}

resp, err := http.DefaultClient.Do(req)
if err !=nil{
    return nil, err
}
defer resp.Body.Close()

b, err := ioutil.ReadAll(resp.Body)
if err !=nil{
    return nil, err
}

return b,nil

如此简单的几行代码,在我们套上大并发以后,各种异常情况接踵而至,最常见的就是下面的几个:

  • EOF
  • connection reset by peer

那具体又是什么原因导致出现上面几种情况呢?

探讨

HTTP也是针对TCP的一个封装,那我们先来简单回归一下?
tcp connect
上面的图向我们展示了TCP连接建立、数据通信以及连接断开的几个步骤,go得益于goroutine和channel,与其他语言的实现方式不太一样,它是直接起了两个协程,一个用于读(readLoop),一个用于写(writeLoop)。我们来看看官方描述:

from:io/io.go

// EOF is the error returned by Read when no more input is available.
// Functions should return EOF only to signal a graceful end of input.
// If the EOF occurs unexpectedly in a structured data stream,
// the appropriate error is either ErrUnexpectedEOF or some other error
// giving more detail.
var EOF = errors.New("EOF")

读写细节

conn.Read

  • socket无数据:read阻塞,直到有数据。
  • socket有部分数据:如果socket中有部分数据,且长度小于一次Read操作所期望读出的数据长度,那么Read将会成功读出这部分数据并返回,而不是等待所有期望数据全部读取后再返回。
  • socket有足够数据:如果socket中有数据,且长度大于等于一次Read操作所期望读出的数据长度,那么Read将会成功读出这部分数据并返回。这个情景是最符合我们对Read的期待的了:Read将用Socket中的数据将我们传入的slice填满后返回:n = 10, err = nil
  • 有数据,socket关闭:第一次Read成功读出了所有的数据,当第二次Read时,由于client端 socket关闭,Read返回EOF error;
  • 无数据,socket关闭:Read直接返回EOF error

    conn.Write

  • 成功写:Write调用返回的n与预期要写入的数据长度相等,且error = nil;
  • 写阻塞:当发送方将对方的接收缓冲区以及自身的发送缓冲区写满后,Write就会阻塞;
  • 写入部分数据:Write操作存在写入部分数据的情况,没有按照预期的写入所有数据,则需要循环写入。

    开方子

    通过上面的描述,我们大致已经明白了为何会出现EOF了,其实就是readLoop在进行读的时候,检测到socket被关闭了。在HTTP1.1,我们默认都是采用了Keep-Alive的,也就是会启动长连接,当server端断掉了该socket后,我们的EOF就出来了。所以尽量避免该情况发生的话,直接这样req.Close = true。

标签: EOF golang
最后更新:2021年8月15日

PingD

反思让我成长

点赞
< 上一篇
下一篇 >

文章评论

取消回复

PingD

反思让我成长

归档
  • 2023年1月
  • 2022年3月
  • 2022年1月
  • 2021年10月
  • 2021年8月
  • 2021年4月
  • 2020年11月
  • 2020年10月
  • 2020年9月
  • 2020年8月
  • 2019年9月
  • 2019年7月
  • 2019年6月
  • 2019年4月
  • 2019年3月
最新 热点 随机
最新 热点 随机
断更了,不想写了 新路由2(newifi d1) 小白刷老毛子固件 2021年度总结 golang之从源码角度看slice的len和cap 基于chan实现的简易协程池及说明 订单超时方案(初稿)
sh、bash和zsh区别 Golang之defer 2021年度总结 Golang之HTTP EOF/connection reset by peer详解 断更了,不想写了 Go之底层利器-AST遍历
最近评论

COPYRIGHT © 2021 dpjeep.com. ALL RIGHTS RESERVED.

THEME KRATOS MADE BY VTROIS

蜀ICP备18036663号-1