W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
?gtcp
?模塊提供了連接池的特性,由?gtcp.PoolConn
?對(duì)象實(shí)現(xiàn),連接池緩存固定存活時(shí)間為600秒,且內(nèi)部實(shí)現(xiàn)了數(shù)據(jù)發(fā)送時(shí)的斷開(kāi)重連機(jī)制。連接池非常適合于頻繁的短鏈接操作且連接并發(fā)量大的場(chǎng)景。我們接下來(lái)使用兩個(gè)示例來(lái)演示一下連接池的作用。
使用方式:
import "github.com/gogf/gf/v2/net/gtcp"
接口文檔:
https://pkg.go.dev/github.com/gogf/gf/v2/net/gtcp
type PoolConn
func NewPoolConn(addr string, timeout ...int) (*PoolConn, error)
func (c *PoolConn) Close() error
func (c *PoolConn) Recv(length int, retry ...Retry) ([]byte, error)
func (c *PoolConn) RecvLine(retry ...Retry) ([]byte, error)
func (c *PoolConn) RecvPkg(option ...PkgOption) ([]byte, error)
func (c *PoolConn) RecvPkgWithTimeout(timeout time.Duration, option ...PkgOption) ([]byte, error)
func (c *PoolConn) RecvWithTimeout(length int, timeout time.Duration, retry ...Retry) (data []byte, err error)
func (c *PoolConn) Send(data []byte, retry ...Retry) error
func (c *PoolConn) SendPkg(data []byte, option ...PkgOption) (err error)
func (c *PoolConn) SendPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) error
func (c *PoolConn) SendRecv(data []byte, receive int, retry ...Retry) ([]byte, error)
func (c *PoolConn) SendRecvPkg(data []byte, option ...PkgOption) ([]byte, error)
func (c *PoolConn) SendRecvPkgWithTimeout(data []byte, timeout time.Duration, option ...PkgOption) ([]byte, error)
func (c *PoolConn) SendRecvWithTimeout(data []byte, receive int, timeout time.Duration, retry ...Retry) ([]byte, error)
func (c *PoolConn) SendWithTimeout(data []byte, timeout time.Duration, retry ...Retry) error
由于?gtcp.PoolConn
?繼承于?gtcp.Conn
?因此同時(shí)也可以使用?gtcp.Conn
?的方法。
package main
import (
"fmt"
"time"
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gtime"
)
func main() {
// Server
go gtcp.NewServer("127.0.0.1:8999", func(conn *gtcp.Conn) {
defer conn.Close()
for {
data, err := conn.Recv(-1)
if len(data) > 0 {
if err := conn.Send(append([]byte("> "), data...)); err != nil {
fmt.Println(err)
}
}
if err != nil {
break
}
}
}).Run()
time.Sleep(time.Second)
// Client
for {
if conn, err := gtcp.NewPoolConn("127.0.0.1:8999"); err == nil {
if b, err := conn.SendRecv([]byte(gtime.Datetime()), -1); err == nil {
fmt.Println(string(b), conn.LocalAddr(), conn.RemoteAddr())
} else {
fmt.Println(err)
}
conn.Close()
} else {
glog.Error(err)
}
time.Sleep(time.Second)
}
}
在這個(gè)示例中,?Server
?創(chuàng)建新的?goroutine
?異步運(yùn)行,?Client
?在?main goroutine
?中執(zhí)行。?Server
?端是一個(gè)回顯服務(wù)器,?Client
?每隔1秒向?Server
?端發(fā)送當(dāng)前的時(shí)間,經(jīng)過(guò)?Server
?端回顯返回后,在?Client
?端打印出雙方的連接端口信息。
執(zhí)行后,結(jié)果如下:
> 2018-07-11 23:29:54 127.0.0.1:55876 127.0.0.1:8999
> 2018-07-11 23:29:55 127.0.0.1:55876 127.0.0.1:8999
> 2018-07-11 23:29:56 127.0.0.1:55876 127.0.0.1:8999
> 2018-07-11 23:29:57 127.0.0.1:55876 127.0.0.1:8999
> 2018-07-11 23:29:58 127.0.0.1:55876 127.0.0.1:8999
...
可以看到,?Client
?的端口一直未變,每一次通過(guò)?gtcp.NewConn("127.0.0.1:8999")
?獲得的都是同一個(gè)?gtcp.Conn
?對(duì)象,且每一次?conn.Close()
?時(shí)并不是真正的關(guān)閉連接,而是將該對(duì)象重新丟回到連接池里循環(huán)使用。
這個(gè)例子是為了展示當(dāng)服務(wù)端關(guān)閉連接后,該連接對(duì)象還是否有效的處理。
package main
import (
"fmt"
"time"
"github.com/gogf/gf/v2/net/gtcp"
"github.com/gogf/gf/v2/os/glog"
"github.com/gogf/gf/v2/os/gtime"
)
func main() {
// Server
go gtcp.NewServer("127.0.0.1:8999", func(conn *gtcp.Conn) {
defer conn.Close()
for {
data, err := conn.Recv(-1)
if len(data) > 0 {
if err := conn.Send(append([]byte("> "), data...)); err != nil {
fmt.Println(err)
}
}
if err != nil {
break
}
return
}
}).Run()
time.Sleep(time.Second)
// Client
for {
if conn, err := gtcp.NewPoolConn("127.0.0.1:8999"); err == nil {
if b, err := conn.SendRecv([]byte(gtime.Datetime()), -1); err == nil {
fmt.Println(string(b), conn.LocalAddr(), conn.RemoteAddr())
} else {
fmt.Println(err)
}
conn.Close()
} else {
glog.Error(err)
}
time.Sleep(time.Second)
}
}
執(zhí)行后,輸出結(jié)果如下:
> 2018-07-20 12:56:15 127.0.0.1:59368 127.0.0.1:8999
EOF
> 2018-07-20 12:56:17 127.0.0.1:59376 127.0.0.1:8999
EOF
> 2018-07-20 12:56:19 127.0.0.1:59378 127.0.0.1:8999
EOF
...
在這個(gè)示例中,?Server
?每處理完畢一條請(qǐng)求之后便關(guān)閉鏈接。?Client
?在第一條請(qǐng)求發(fā)送完畢后,由于連接池的?IO
?復(fù)用特性,下一次獲取到的將是同一個(gè)連接對(duì)象,由于?Server
?鏈接已主動(dòng)關(guān)閉,第二次請(qǐng)求寫(xiě)入成功(其實(shí)并未成功發(fā)送到?Server
?端,需要通過(guò)下一次的讀取操作才能檢測(cè)到鏈接錯(cuò)誤),但是讀取卻失敗了(?EOF
?表示目標(biāo)連接關(guān)閉),因此這個(gè)時(shí)候?Client
?執(zhí)行?Close
?時(shí)將會(huì)銷(xiāo)毀該連接操作對(duì)象,而不是進(jìn)一步復(fù)用。下一次再通過(guò)?gtcp.NewPoolConn
?獲得連接對(duì)象時(shí),?Client
?將會(huì)與?Server
?創(chuàng)建一個(gè)新的連接進(jìn)行數(shù)據(jù)通信。所以你看到?Client
?的端口一直在變化,那是因?yàn)樵?gtcp.Conn
?對(duì)象已經(jīng)是一個(gè)新的連接對(duì)象,之前的連接對(duì)象已經(jīng)被銷(xiāo)毀。
連接對(duì)象的?IO
?復(fù)用涉及到十分微妙的連接狀態(tài)變化問(wèn)題,由于點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)通信本身是比較復(fù)雜的環(huán)境,連接對(duì)象的狀態(tài)隨時(shí)可能被動(dòng)發(fā)生著變化,因此,在使用?gtcp
?連接池特性時(shí),需要注意當(dāng)通信錯(cuò)誤產(chǎn)生時(shí)的連接對(duì)象重建機(jī)制,一旦產(chǎn)生錯(cuò)誤,立即丟棄(?Close
?)該對(duì)象(?gtcp.PoolConn
?)并重建(?gtcp.NewPoolConn
?)。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: