Sockets 插座可以';t识别协议(套接字泄漏)

Sockets 插座可以';t识别协议(套接字泄漏),sockets,go,Sockets,Go,我有一个Go1.5.1进程/应用程序。当我在这个进程上运行/usr/sbin/lsof-p时,我看到很多“无法识别协议” 过程状态/限制/fd [root@Monitor_q ~]# cat /proc/13105/status Name: monitor_client State: S (sleeping) Tgid: 13105 Pid: 13105 PPid: 13104 TracerPid: 0 Uid: 0 0 0 0 Gid: 0

我有一个Go1.5.1进程/应用程序。当我在这个进程上运行
/usr/sbin/lsof-p
时,我看到很多“无法识别协议”

过程状态/限制/fd

[root@Monitor_q ~]# cat /proc/13105/status 
Name:   monitor_client
State:  S (sleeping)
Tgid:   13105
Pid:    13105
PPid:   13104
TracerPid:  0
Uid:    0   0   0   0
Gid:    0   0   0   0
Utrace: 0
FDSize: 16384
Groups: 
...


[root@Monitor_q ~]# cat /proc/13105/limits 
Limit                     Soft Limit           Hard Limit           Units     
Max cpu time              unlimited            unlimited            seconds   
Max file size             unlimited            unlimited            bytes     
Max data size             unlimited            unlimited            bytes     
Max stack size            10485760             unlimited            bytes     
Max core file size        0                    unlimited            bytes     
Max resident set          unlimited            unlimited            bytes     
Max processes             3870                 3870                 processes 
Max open files            9999                 9999                 files     
Max locked memory         65536                65536                bytes     
Max address space         unlimited            unlimited            bytes     
Max file locks            unlimited            unlimited            locks     
Max pending signals       3870                 3870                 signals   
Max msgqueue size         819200               819200               bytes     
Max nice priority         0                    0                    
Max realtime priority     0                    0                    
Max realtime timeout      unlimited            unlimited            us

[root@Monitor_q ~]# ll /proc/13105/fd/
lrwx------ 1 root root 64 Dec  7 00:15 8382 -> socket:[52023221]
lrwx------ 1 root root 64 Dec  7 00:15 8383 -> socket:[51186627]
lrwx------ 1 root root 64 Dec  7 00:15 8384 -> socket:[51864232]
lrwx------ 1 root root 64 Dec  7 00:15 8385 -> socket:[52435453]
lrwx------ 1 root root 64 Dec  7 00:15 8386 -> socket:[51596071]
lrwx------ 1 root root 64 Dec  7 00:15 8387 -> socket:[52767667]
lrwx------ 1 root root 64 Dec  7 00:15 8388 -> socket:[52090632]
lrwx------ 1 root root 64 Dec  7 00:15 8389 -> socket:[51739068]
lrwx------ 1 root root 64 Dec  7 00:15 839 -> socket:[22963529]
lrwx------ 1 root root 64 Dec  7 00:15 8390 -> socket:[52023223]
lrwx------ 1 root root 64 Dec  7 00:15 8391 -> socket:[52560389]
lrwx------ 1 root root 64 Dec  7 00:15 8392 -> socket:[52402565]
...
但是在
netstat-a
中没有类似的输出

这些插座是什么?我怎样才能知道它们是做什么的

monitor_client.go

package main

import (
    "crypto/tls"
    "encoding/json"
    "fmt"
    "log"
    "net"
    "net/http"
    nurl "net/url"
    "strconv"
    "strings"
    "syscall"
    "time"
)

type Result struct {
    Error      string        `json:"error"`
    HttpStatus int           `json:"http_status"`
    Stime      time.Duration `json:"http_time"`
}

//http://stackoverflow.com/questions/20990332/golang-http-timeout-and-goroutines-accumulation
//http://3.3.3.3/http?host=3.2.4.2&servername=a.test&path=/&port=33&timeout=5&scheme=http
func MonitorHttp(w http.ResponseWriter, r *http.Request) {
    var host, servername, path, port, scheme string
    var timeout int
    u, err := nurl.Parse(r.RequestURI)
    if err != nil {
        log.Fatal(err)
        return
    }
    if host = u.Query().Get("host"); host == "" {
        host = "127.0.0.0"
    }
    if servername = u.Query().Get("servername"); servername == "" {
        servername = "localhost"
    }
    if path = u.Query().Get("path"); path == "" {
        path = "/"
    }
    if port = u.Query().Get("port"); port == "" {
        port = "80"
    }
    if scheme = u.Query().Get("scheme"); scheme == "" {
        scheme = "http"
    }

    if timeout, _ = strconv.Atoi(u.Query().Get("timeout")); timeout == 0 {
        timeout = 5
    }

    //log.Printf("(host)=%s (servername)=%s (path)=%s (port)=%s (timeout)=%d", host, servername, path, port, timeout)

    w.Header().Set("Content-Type", "application/json")

    res := httptool(host, port, servername, scheme, path, timeout)
    result, _ := json.Marshal(res)
    fmt.Fprintf(w, "%s", result)
}

func httptool(ip, port, servername, scheme, path string, timeout int) Result {

    var result Result
    startTime := time.Now()
    host := ip + ":" + port

    transport := &http.Transport{
        TLSClientConfig:   &tls.Config{InsecureSkipVerify: true},
        DisableKeepAlives: true,
    }

    dialer := net.Dialer{
        Timeout:   time.Duration(timeout) * time.Second,
        KeepAlive: 0 * time.Second,
    }
    transport.Dial = func(network, address string) (net.Conn, error) {
        return dialer.Dial(network, address)
    }

    client := &http.Client{
        Transport: transport,
    }
    rawquery := ""
    url := fmt.Sprintf("%s://%s%s%s", scheme, host, path, rawquery)
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        result.HttpStatus = -1
        errs := strings.Split(err.Error(), ": ")
        result.Error = errs[len(errs)-1]
        result.Stime = time.Now().Sub(startTime) / time.Millisecond
        return result
    }
    req.Header.Set("User-Agent", "monitor worker")
    req.Header.Set("Connection", "close")
    req.Host = servername
    resp, err := client.Do(req)
    //https://github.com/Basiclytics/neverdown/blob/master/check.go
    if err != nil {
        nerr, ok := err.(*nurl.Error)
        if ok {
            switch cerr := nerr.Err.(type) {
            case *net.OpError:
                switch cerr.Err.(type) {
                case *net.DNSError:
                    errs := strings.Split(cerr.Error(), ": ")
                    result.Error = "dns: " + errs[len(errs)-1]
                default:
                    errs := strings.Split(cerr.Error(), ": ")
                    result.Error = "server: " + errs[len(errs)-1]
                }
            default:
                switch nerr.Err.Error() {
                case "net/http: request canceled while waiting for connection":
                    errs := strings.Split(cerr.Error(), ": ")
                    result.Error = "timeout: " + errs[len(errs)-1]

                default:
                    errs := strings.Split(cerr.Error(), ": ")
                    result.Error = "unknown: " + errs[len(errs)-1]
                }
            }

        } else {
            result.Error = "unknown: " + err.Error()
        }
        result.HttpStatus = -2
        result.Stime = time.Now().Sub(startTime) / time.Millisecond
        return result
    }
    resp.Body.Close()
    result.HttpStatus = resp.StatusCode
    result.Error = "noerror"
    result.Stime = time.Now().Sub(startTime) / time.Millisecond //spend time (ms)
    return result
}

func setRlimit() {
    var rLimit syscall.Rlimit
    err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
    if err != nil {
        log.Printf("Unable to obtain rLimit", err)
    }
    if rLimit.Cur < rLimit.Max {
        rLimit.Max = 9999
        rLimit.Cur = 9999
        err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
        if err != nil {
            log.Printf("Unable to increase number of open files limit", err)
        }
    }
}

func main() {
    setRlimit()
    s := &http.Server{
        Addr:         ":59059",
        ReadTimeout:  7 * time.Second,
        WriteTimeout: 7 * time.Second,
    }
    http.HandleFunc("/http", MonitorHttp)

    log.Fatal(s.ListenAndServe())
}
主程序包
进口(
“加密/tls”
“编码/json”
“fmt”
“日志”
“净额”
“net/http”
nurl“网络/网址”
“strconv”
“字符串”
“系统调用”
“时间”
)
类型结果结构{
错误字符串`json:“错误”`
HttpStatus int`json:“http_状态”`
time.Duration`json:“http_time”`
}
//http://stackoverflow.com/questions/20990332/golang-http-timeout-and-goroutines-accumulation
//http://3.3.3.3/http?host=3.2.4.2&servername=a.test&path=/&port=33&timeout=5&scheme=http
func MonitorHttp(w http.ResponseWriter,r*http.Request){
变量主机、服务器名、路径、端口、方案字符串
变量超时整型
u、 err:=nurl.Parse(r.RequestURI)
如果错误!=零{
log.Fatal(错误)
返回
}
如果host=u.Query().Get(“主机”);host==“”{
host=“127.0.0.0”
}
如果servername=u.Query().Get(“servername”);servername==“”{
servername=“localhost”
}
如果路径=u.Query().Get(“路径”);路径=“”{
path=“/”
}
如果端口=u.Query().Get(“端口”);端口=“”{
port=“80”
}
如果scheme=u.Query().Get(“scheme”);scheme==“”{
scheme=“http”
}
如果超时,则=strconv.Atoi(u.Query().Get(“超时”);超时==0{
超时=5
}
//log.Printf(((主机)=%s(服务器名)=%s(路径)=%s(端口)=%s(超时)=%d),主机、服务器名、路径、端口、超时)
w、 Header().Set(“内容类型”、“应用程序/json”)
res:=httptool(主机、端口、服务器名、方案、路径、超时)
结果:=json.Marshal(res)
fmt.Fprintf(w,“%s”,结果)
}
func httptool(ip、端口、服务器名、方案、路径字符串、超时int)结果{
var结果
开始时间:=时间。现在()
主机:=ip+“:”+端口
传输:=&http.transport{
TLSClientConfig:&tls.Config{unsecureskipverify:true},
不可禁用的keepalives:true,
}
拨号器:=网络拨号器{
超时:时间。持续时间(超时)*时间。秒,
保持生命:0*次。秒,
}
transport.Dial=func(网络,地址字符串)(net.Conn,错误){
返回拨号器。拨号(网络、地址)
}
客户端:=&http.client{
运输:运输,,
}
rawquery:=“”
url:=fmt.Sprintf(“%s://%s%s%s”,方案,主机,路径,rawquery)
req,err:=http.NewRequest(“GET”,url,nil)
如果错误!=零{
result.HttpStatus=-1
errs:=strings.Split(err.Error(),“:”)
result.Error=errs[len(errs)-1]
result.Stime=time.Now().Sub(startTime)/time.毫秒
返回结果
}
请求头集合(“用户代理”、“监视器工作程序”)
请求标题集(“连接”、“关闭”)
req.Host=servername
resp,err:=client.Do(请求)
//https://github.com/Basiclytics/neverdown/blob/master/check.go
如果错误!=零{
nerr,ok:=错误。(*nurl.Error)
如果可以的话{
开关cerr:=nerr.Err.(类型){
case*net.OpError:
开关cerr.Err.(类型){
案例*net.DNSError:
errs:=strings.Split(cerr.Error(),“:”)
result.Error=“dns:+errs[len(errs)-1]
违约:
errs:=strings.Split(cerr.Error(),“:”)
result.Error=“服务器:”+errs[len(errs)-1]
}
违约:
开关nerr.Err.Error(){
案例“net/http:在等待连接时取消请求”:
errs:=strings.Split(cerr.Error(),“:”)
result.Error=“timeout:+errs[len(errs)-1]
违约:
errs:=strings.Split(cerr.Error(),“:”)
result.Error=“未知:”+errs[len(errs)-1]
}
}
}否则{
result.Error=“未知:”+err.Error()
}
result.HttpStatus=-2
result.Stime=time.Now().Sub(startTime)/time.毫秒
返回结果
}
各自主体关闭()
result.HttpStatus=resp.StatusCode
result.Error=“noerror”
result.Stime=time.Now().Sub(startTime)/time.毫秒//花费时间(ms)
返回结果
}
func setRlimit(){
var rLimit syscall.rLimit
err:=syscall.Getrlimit(syscall.RLIMIT_NOFILE,&RLIMIT)
如果错误!=零{
log.Printf(“无法获取rLimit”,错误)
}
如果rLimit.Cur
这里有几点

我无法重现您的行为,无论如何,
无法识别协议
通常与未正确关闭的套接字绑定

一些评论员建议您不必在每个处理程序中创建http客户机-这是事实。只需创建一次并重用即可

其次,我不知道为什么要创建自己的
http.Client
struct,为什么要禁用keepalives。你不能直接使用http.Get?更简单的代码更容易调试

第三,不确定为什么要覆盖传输拨号功能。即使您必须这样做,文档(适用于Go 1.9.2)也会说:

关于反对和缺少拨号盘的评论
package main

import (
    "crypto/tls"
    "encoding/json"
    "fmt"
    "log"
    "net"
    "net/http"
    nurl "net/url"
    "strconv"
    "strings"
    "syscall"
    "time"
)

type Result struct {
    Error      string        `json:"error"`
    HttpStatus int           `json:"http_status"`
    Stime      time.Duration `json:"http_time"`
}

//http://stackoverflow.com/questions/20990332/golang-http-timeout-and-goroutines-accumulation
//http://3.3.3.3/http?host=3.2.4.2&servername=a.test&path=/&port=33&timeout=5&scheme=http
func MonitorHttp(w http.ResponseWriter, r *http.Request) {
    var host, servername, path, port, scheme string
    var timeout int
    u, err := nurl.Parse(r.RequestURI)
    if err != nil {
        log.Fatal(err)
        return
    }
    if host = u.Query().Get("host"); host == "" {
        host = "127.0.0.0"
    }
    if servername = u.Query().Get("servername"); servername == "" {
        servername = "localhost"
    }
    if path = u.Query().Get("path"); path == "" {
        path = "/"
    }
    if port = u.Query().Get("port"); port == "" {
        port = "80"
    }
    if scheme = u.Query().Get("scheme"); scheme == "" {
        scheme = "http"
    }

    if timeout, _ = strconv.Atoi(u.Query().Get("timeout")); timeout == 0 {
        timeout = 5
    }

    //log.Printf("(host)=%s (servername)=%s (path)=%s (port)=%s (timeout)=%d", host, servername, path, port, timeout)

    w.Header().Set("Content-Type", "application/json")

    res := httptool(host, port, servername, scheme, path, timeout)
    result, _ := json.Marshal(res)
    fmt.Fprintf(w, "%s", result)
}

func httptool(ip, port, servername, scheme, path string, timeout int) Result {

    var result Result
    startTime := time.Now()
    host := ip + ":" + port

    transport := &http.Transport{
        TLSClientConfig:   &tls.Config{InsecureSkipVerify: true},
        DisableKeepAlives: true,
    }

    dialer := net.Dialer{
        Timeout:   time.Duration(timeout) * time.Second,
        KeepAlive: 0 * time.Second,
    }
    transport.Dial = func(network, address string) (net.Conn, error) {
        return dialer.Dial(network, address)
    }

    client := &http.Client{
        Transport: transport,
    }
    rawquery := ""
    url := fmt.Sprintf("%s://%s%s%s", scheme, host, path, rawquery)
    req, err := http.NewRequest("GET", url, nil)
    if err != nil {
        result.HttpStatus = -1
        errs := strings.Split(err.Error(), ": ")
        result.Error = errs[len(errs)-1]
        result.Stime = time.Now().Sub(startTime) / time.Millisecond
        return result
    }
    req.Header.Set("User-Agent", "monitor worker")
    req.Header.Set("Connection", "close")
    req.Host = servername
    resp, err := client.Do(req)
    //https://github.com/Basiclytics/neverdown/blob/master/check.go
    if err != nil {
        nerr, ok := err.(*nurl.Error)
        if ok {
            switch cerr := nerr.Err.(type) {
            case *net.OpError:
                switch cerr.Err.(type) {
                case *net.DNSError:
                    errs := strings.Split(cerr.Error(), ": ")
                    result.Error = "dns: " + errs[len(errs)-1]
                default:
                    errs := strings.Split(cerr.Error(), ": ")
                    result.Error = "server: " + errs[len(errs)-1]
                }
            default:
                switch nerr.Err.Error() {
                case "net/http: request canceled while waiting for connection":
                    errs := strings.Split(cerr.Error(), ": ")
                    result.Error = "timeout: " + errs[len(errs)-1]

                default:
                    errs := strings.Split(cerr.Error(), ": ")
                    result.Error = "unknown: " + errs[len(errs)-1]
                }
            }

        } else {
            result.Error = "unknown: " + err.Error()
        }
        result.HttpStatus = -2
        result.Stime = time.Now().Sub(startTime) / time.Millisecond
        return result
    }
    resp.Body.Close()
    result.HttpStatus = resp.StatusCode
    result.Error = "noerror"
    result.Stime = time.Now().Sub(startTime) / time.Millisecond //spend time (ms)
    return result
}

func setRlimit() {
    var rLimit syscall.Rlimit
    err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit)
    if err != nil {
        log.Printf("Unable to obtain rLimit", err)
    }
    if rLimit.Cur < rLimit.Max {
        rLimit.Max = 9999
        rLimit.Cur = 9999
        err = syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rLimit)
        if err != nil {
            log.Printf("Unable to increase number of open files limit", err)
        }
    }
}

func main() {
    setRlimit()
    s := &http.Server{
        Addr:         ":59059",
        ReadTimeout:  7 * time.Second,
        WriteTimeout: 7 * time.Second,
    }
    http.HandleFunc("/http", MonitorHttp)

    log.Fatal(s.ListenAndServe())
}
% go doc http.transport.dial
type Transport struct {
    // Dial specifies the dial function for creating unencrypted TCP
    connections.
    //
    // Deprecated: Use DialContext instead, which allows the transport
    // to cancel dials as soon as they are no longer needed.
    // If both are set, DialContext takes priority.
    Dial func(network, addr string) (net.Conn, error)