前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言 如果实现http重连?

Go语言 如果实现http重连?

作者头像
李海彬
发布2018-03-19 15:30:00
1.1K0
发布2018-03-19 15:30:00
举报
文章被收录于专栏:Golang语言社区Golang语言社区

怎样做到每次使用一个连接发送和接收前就设置超时呢?我想了个办法是在Dial回调返回自己包装过的TimeoutConn,间接的调用真实的Conn,这样就可以再每次Read和Write之前设置超时时间了。

以下是修改后的实验代码:

代码语言:javascript
复制
//

// How to set timeout for http.Get() in golang

//

package main



import (

    "io"

    "io/ioutil"

    "log"

    "net"

    "net/http"

    "sync"

    "time"

)



type TimeoutConn struct {

    conn    net.Conn

    timeout time.Duration

}



func NewTimeoutConn(conn net.Conn, timeout time.Duration) *TimeoutConn {

    return &TimeoutConn{

        conn:    conn,

        timeout: timeout,

    }

}



func (c *TimeoutConn) Read(b []byte) (n int, err error) {

    c.SetReadDeadline(time.Now().Add(c.timeout))

    return c.conn.Read(b)

}



func (c *TimeoutConn) Write(b []byte) (n int, err error) {

    c.SetWriteDeadline(time.Now().Add(c.timeout))

    return c.conn.Write(b)

}



func (c *TimeoutConn) Close() error {

    return c.conn.Close()

}



func (c *TimeoutConn) LocalAddr() net.Addr {

    return c.conn.LocalAddr()

}



func (c *TimeoutConn) RemoteAddr() net.Addr {

    return c.conn.RemoteAddr()

}



func (c *TimeoutConn) SetDeadline(t time.Time) error {

    return c.conn.SetDeadline(t)

}



func (c *TimeoutConn) SetReadDeadline(t time.Time) error {

    return c.conn.SetReadDeadline(t)

}



func (c *TimeoutConn) SetWriteDeadline(t time.Time) error {

    return c.conn.SetWriteDeadline(t)

}



func main() {

    client := &http.Client{

        Transport: &http.Transport{

            Dial: func(netw, addr string) (net.Conn, error) {

                log.Printf("dial to %s://%s", netw, addr)



                conn, err := net.DialTimeout(netw, addr, time.Second*2)



                if err != nil {

                    return nil, err

                }



                return NewTimeoutConn(conn, time.Second*2), nil

            },

            ResponseHeaderTimeout: time.Second * 2,

        },

    }



    addr := StartTestServer()



    SendTestRequest(client, "1st", addr, "normal")

    SendTestRequest(client, "2st", addr, "normal")

    SendTestRequest(client, "3st", addr, "timeout")

    SendTestRequest(client, "4st", addr, "normal")



    time.Sleep(time.Second * 3)



    SendTestRequest(client, "5st", addr, "normal")

}



func StartTestServer() string {

    listener, err := net.Listen("tcp", ":0")



    if err != nil {

        log.Fatalf("failed to listen - %s", err.Error())

    }



    wg := new(sync.WaitGroup)

    wg.Add(1)



    go func() {

        http.HandleFunc("/normal", func(w http.ResponseWriter, req *http.Request) {

            time.Sleep(1000 * time.Millisecond)

            io.WriteString(w, "ok")

        })



        http.HandleFunc("/timeout", func(w http.ResponseWriter, req *http.Request) {

            time.Sleep(2500 * time.Millisecond)

            io.WriteString(w, "ok")

        })



        wg.Done()



        err = http.Serve(listener, nil)



        if err != nil {

            log.Fatalf("failed to start HTTP server - %s", err.Error())

        }

    }()



    wg.Wait()



    log.Printf("start http server at http://%s/", listener.Addr())



    return listener.Addr().String()

}



func SendTestRequest(client *http.Client, id, addr, path string) {

    req, err := http.NewRequest("GET", "http://"+addr+"/"+path, nil)



    if err != nil {

        log.Fatalf("new request failed - %s", err)

    }



    req.Header.Add("Connection", "keep-alive")



    switch path {

    case "normal":

        if resp, err := client.Do(req); err != nil {

            log.Fatalf("%s request failed - %s", id, err)

        } else {

            result, err2 := ioutil.ReadAll(resp.Body)

            if err2 != nil {

                log.Fatalf("%s response read failed - %s", id, err2)

            }

            resp.Body.Close()

            log.Printf("%s request - %s", id, result)

        }

    case "timeout":

        if _, err := client.Do(req); err == nil {

            log.Fatalf("%s request not timeout", id)

        } else {

            log.Printf("%s request - %s", id, err)

        }

    }

}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-01-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档