记一次CLOSE_WAIT

背景:

预发布环境在拉取代码时,页面报Curl Failed :Connection reset by peer ,php后台报connection timeout是php代码部分调用拉取接口时报出来的,通过netstat查看该接口目前的tcp连接状态

 

 

可以看到服务端的连接一直处于close_wait状态,连接一直没释放掉,由于该接口是单线程的,导致新的请求一直阻塞(从第二列可以看到),用户发现一直响应不了就会频繁刷新网页,导致连接数剧增

第二列和第三列的含义如下:

 

第二列表示网络接收队列(recv-Q)

表示收到的数据已经在本地缓冲区,但是还有多少没有被对端服务取走,
如果接收队列Recv-Q一直处于阻塞状态,可能是遭受了拒绝服务 denial-of-service 攻击,说白了就是产生了很多连接导致服务端处理不过来了。

 

第三列表示网路发送队列(send-Q)

对方没有收到的数据或者说没有Ack的,还是本地缓冲区.
如果发送队列Send-Q不能很快的清零,可能是有应用向外发送数据包过快,或者是对方接收数据包过慢。

 

这个问题可以通过一下代码复现

 

服务端

 

复制代码
package main

import (
    "net"
    "time"
)

func main() {
    listen, err := net.Listen("tcp", "127.0.0.1:8888")
    if err != nil {
        panic(err)
    }
    defer listen.Close()

    for {
        conn, err := listen.Accept()
        if err != nil {
            panic(err)
        }
        time.Sleep(20*time.Second)
        conn.Close()
    }
}
复制代码

 

客户端

 

复制代码
package main

import (
    "log"
    "net"
    "time"
)

func main(){
    conn, err := net.Dial("tcp", "127.0.0.1:8888")
    if err != nil {
        log.Println("dial error:", err)
        return
    }
    defer conn.Close()
    time.Sleep(1*time.Second)
    buf := make([]byte, 1024)
    n, err := conn.Write(buf)
    log.Println(n, err)

}
复制代码

 

 

客户端和服务端建立连接后,发送1024字节的数据包,服务端收到请求后,一直不处理数据,直到20s后退出,此时通过netstat查看

 

 

 

可以看到网络接收队列(recv-Q)里的数据一直阻塞没有被服务端处理。

 

 

解决思路

 将服务改为多线程,加快服务端的处理速度。

 

posted @   独揽风月  阅读(212)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示