package main
import (
"net/http"
log "github.com/sirupsen/logrus"
"io/ioutil"
"fmt"
"bytes"
"sync"
_"time"
)
func main() {
var wg sync.WaitGroup
var count int
var rw sync.RWMutex
TEST:
for i := 0; i < 1; i++ {
wg.Add(1)
go func () {
defer wg.Done()
tr := http.Transport{DisableKeepAlives: false}
client := &http.Client{Transport: &tr}
for {
f, err := ioutil.ReadFile("data")
if err != nil {
fmt.Println("read file err", err)
return
}
fmt.Println(len(f))
reader := bytes.NewReader(f)
rw.Lock()
count += 1
index := count
rw.Unlock()
resp, err := client.Post("http://0.0.0.0:8888", "application/x-www-form-urlencoded", reader)
if err != nil {
rw.RLock()
currentCount := count
rw.RUnlock()
log.Fatal(err, index, currentCount)
}
defer resp.Body.Close()
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
log.Printf("data[%s]", string(data))
// time.Sleep(time.Second)
}
}()
}
wg.Wait()
goto TEST
}複製代碼
package main
import (
"fmt"
"io"
"io/ioutil"
"net/http"
"time"
"context"
)
type myHandler struct {
}
func (h myHandler)ServeHTTP(w http.ResponseWriter, r *http.Request) {
//print header
// fmt.Println("header", r.Header)
//debug body
_, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println("read body error", err)
io.WriteString(w, "read you body error!")
return
}
// fmt.Println("data len", len(data))
io.WriteString(w, "goad it")
return
}
func main() {
// http.HandleFunc("/", myHandler)
// err := http.ListenAndServe("0.0.0.0:8888", nil)
// if err != nil {
// fmt.Println("ListenAndServe error", err)
// return
// }
server := &http.Server {
Addr: "0.0.0.0:8888",
Handler: myHandler{},
}
d := time.Duration(time.Second*10)
t := time.NewTimer(d)
defer t.Stop()
go func (){
<- t.C
shutdown(server)
}()
server.ListenAndServe()
for {
fmt.Println(1)
time.Sleep(time.Second)
}
fmt.Println(2)
return
}
func shutdown(server *http.Server) {
ctx, cancel := context.WithTimeout(context.TODO(), 3600)
defer cancel()
server.Shutdown(ctx)
}
複製代碼
func (s *Server) doKeepAlives() bool { return atomic.LoadInt32(&s.disableKeepAlives) == 0 && !s.shuttingDown()}func (s *Server) shuttingDown() bool { return atomic.LoadInt32(&s.inShutdown) != 0}複製代碼
//在go1.10 net/http/server.go 1845行 if !w.conn.server.doKeepAlives() { // We're in shutdown mode. We might've replied // to the user without "Connection: close" and // they might think they can send another // request, but such is life with HTTP/1.1. return }複製代碼
複製代碼
因此在懷疑close的方式致使出現這種狀況,因此針對長鏈接,若是客戶端持續的發送數據可能會出現這種狀況。git
爲了驗證下,我改了closeIdles的代碼,改爲了只關閉服務端的寫,讓客戶端能把數據發送過來github
穩定是有四次揮手的,可是客戶端仍是收到了EOF,服務端不是優雅的。app
再改動下,讓shutdown退出以前sleep了500毫秒tcp
紅色的RST忽略,那是客戶端發起的從新鏈接測試
因此初步結論就是server沒法作到真正的graceful。ui