package main
import (
"net/http"
log "github.com/sirupsen/logrus"
"io/ioutil"
"fmt"
"bytes"
"sync"
)
func main() {
var wg sync.WaitGroup
var count int
var rw sync.RWMutex
TEST:
for i := 0; i < 30; i++ {
wg.Add(1)
go func () {
defer wg.Done()
tr := http.Transport{DisableKeepAlives: false}
client := &http.Client{Transport: &tr}
for i := 0; i < 1000; i++ {
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))
}
}()
}
wg.Wait()
goto TEST
}複製代碼
golang server代碼git
package main
import (
graceful "github.com/cgCodeLife/graceful2"
"net/http"
log "github.com/sirupsen/logrus"
"io/ioutil"
"fmt"
"os"
"strconv"
)
func main() {
server := graceful.NewServer()
handler := http.HandlerFunc(handle)
server.Register("0.0.0.0:8888", handler)
err := server.Run()
if err != nil {
log.Fatal(err)
}
}
func handle(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close()
_, err := ioutil.ReadAll(r.Body)
if err != nil {
fmt.Println("read body error[%s] pid[%d]", err, os.Getpid())
}
w.Write([]byte(strconv.Itoa(os.Getpid())))
}複製代碼
// shutdownPollInterval is how often we poll for quiescence
// during Server.Shutdown. This is lower during tests, to
// speed up tests.
// Ideally we could find a solution that doesn't involve polling, // but which also doesn't have a high runtime cost (and doesn't // involve any contentious mutexes), but that is left as an // exercise for the reader. var shutdownPollInterval = 500 * time.Millisecond // Shutdown gracefully shuts down the server without interrupting any // active connections. Shutdown works by first closing all open // listeners, then closing all idle connections, and then waiting // indefinitely for connections to return to idle and then shut down. // If the provided context expires before the shutdown is complete, // Shutdown returns the context's error, otherwise it returns any
// error returned from closing the Server's underlying Listener(s). // // When Shutdown is called, Serve, ListenAndServe, and // ListenAndServeTLS immediately return ErrServerClosed. Make sure the // program doesn't exit and waits instead for Shutdown to return.
//
// Shutdown does not attempt to close nor wait for hijacked
// connections such as WebSockets. The caller of Shutdown should
// separately notify such long-lived connections of shutdown and wait
// for them to close, if desired. See RegisterOnShutdown for a way to
// register shutdown notification functions.
func (srv *Server) Shutdown(ctx context.Context) error {
atomic.AddInt32(&srv.inShutdown, 1)
defer atomic.AddInt32(&srv.inShutdown, -1)
srv.mu.Lock()
lnerr := srv.closeListenersLocked()
srv.closeDoneChanLocked()
for _, f := range srv.onShutdown {
go f()
}
srv.mu.Unlock()
ticker := time.NewTicker(shutdownPollInterval)
defer ticker.Stop()
for {
if srv.closeIdleConns() {
return lnerr
}
select {
case <-ctx.Done():
return ctx.Err()
case <-ticker.C:
}
}
}複製代碼