Go實現FastCgi Proxy Client 系列(四) keep-alive實現 原 薦

先貼幾個鏈接

前三篇

Go實現FastCgi Proxy Client 系列(三)

Go實現FastCgi Proxy Client 系列(二)

Go實現FastCgi Proxy Client 系列(一)

靈感帖

TCP keepalive 和 http keep-alive

FastCGI Specification

Golang 優化之路——HTTP長連接

go HTTP Client大量長連接保持

很感謝上面幾個文章,讓我突然想通了我之前一直沒搞懂的問題,雖然問題不是一種,但是也算是旁敲側擊的讓我茅塞頓開了,非常感謝!

分析

協議

麻省理工學院的文檔上是這麼描述的:

The flags component contains a bit that controls connection shutdown:

flags & FCGI_KEEP_CONN: If zero, the application closes the connection after responding to this request. If not zero, the application does not close the connection after responding to this request; the Web server retains responsibility for the connection.

好吧,高大上的描述。各種文檔裏對fastcgi協議裏沒怎麼講keep-alive的作用,就只是很簡單的說了,如果是開啓了,就能讓http連接進行復用。然而按照之前的知識(我沒跟上時代啊),http協議是無狀態的協議,死活我也是想不通如何連接複用。

然而我忘記了,http也是基於tcp協議的,tcp一般而言,如果你不手動進行斷開,或者網絡原因引起的話,是會保持一個長連接的(通常都會設置超時)。

盜張圖:

輸入圖片說明

可以看出,假如,我們不進行最後的4次揮手操作,在超時範圍內,這個tcp連接是不會斷開的。

代碼

然後我再去看go官方對fastcgi協議的實現,我發現一個很重要的地方(源碼位置 net/http/fastcgi/child.go):

當用戶發起終止信號的時候,keep-alive起了作用,那就是說,我的proxy層只要不進行斷開連接,這個tcp連接就依然還是可用的。

case typeAbortRequest:
		//......
		if !req.keepConn {
			// connection will close upon return
			return errCloseConn
		}
		return nil

然後,我繼續閱讀源碼,此時,我要唱一下,“終於等到你,還好我沒忘記”。果然是這樣,如果鏈接不是keep-alive,會即時關閉tcp連接。

func (c *child) serveRequest(req *request, body io.ReadCloser) {
	//......

	if !req.keepConn {
		c.conn.Close()
	}
}

修改實現

在我們讀取數據的位置,我們進行相關操作即可,如果,請求不是keep-alive 自然,返回值會包含終止符 EOF,這時可以直接返回;反之,如果是keep-alive,則會每個請求都獲得到一個typeEndRequest(值爲3,具體請看第一篇)的標識

// recive untill EOF or FCGI_END_REQUEST
	for {
		err1 = rec.read(cgi.rwc)
		//if !keep-alive the end has EOF
		if err1 != nil {
			if err1 != io.EOF {
				err = err1
			}
			break
		}

		switch {
		case rec.h.Type == typeStdout:
			retout = append(retout, rec.content()...)
		case rec.h.Type == typeStderr:
			reterr = append(reterr, rec.content()...)
		case rec.h.Type == typeEndRequest:
			//if keep-alive
			//It's had return
			//But connection Not close
			retout = append(retout, rec.content()...)
			return
		default:
			//fallthrough
		}
	}

總結

個人總結

那,其實很簡單不是嘛?我之前只是理解錯了typeEndRequest這個類型,我把他當成了錯誤的時候纔會返回,報了一個fallthrough。更簡單的一句就是,複用的不是http,不是http,不是!複用的tcp!tcp!tcp!

然後,當遇到一個自己暫時無法理解的問題時候,可能你已經鑽入了死衚衕。這個時候,你可以放鬆自己精神,玩玩遊戲,運動運動都行(哈哈,這個問題我都忘記一個月了,感謝羣友的問題,雖然我沒幫他解決,但是他提示了我,我還要沒解決的問題)。

下一步

下一步,將會對超時進行設置。

spinx(小玩具)

一個實現對fastcgi協議的轉發小玩具。

Quick Start

go get github.com/lwl1989/spinx

cd $gopath/src/github.com/lwl1989/spinx

go build -o spinx main.go

Install

sudo ./spinx  -c=config_path install

Remove

sudo ./spinx  remove

Start

sudo ./spinx start
or
./spinx -d=false -c=config_path

Stop

sudo ./spinx stop
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章