golang開發的工程經驗積累(一)
1,自訂結構體維護使用者和對應的tcp連結
可以使用map來維護這個資訊,但這樣一旦串連的使用者數目較多,則map會過大而降低查詢的效率,所以可以自訂結構體:
type User struct { uid int64 conn *CConn ticked bool // 多次串連導致當前串連被踢下 beatTimeOut bool // 心跳檢測逾時 ...}type CConn struct{ conn net.Conn // 網路連接 lastTime time.Time // 最近一次通訊時間 addr string // 串連的唯一識別碼 user *User // User與CConn一一映射}
然後在建立串連時
func CListenAndServe(net, addr string) { tcpAddr, err := net.ResolveTCPAddr(net,addr) if err != nil { // error handling } listener, err := net.listenTCP(net, tcpAddr) if err != nil { //error handling } go accept() //因為go協程的建立開銷非常小}func accpet() { for { conn, err := listener.AcceptTCP() if err == nil { // 發包頻率統計,避免頻繁串連 // 黑白名單 newconn := NewCConn(conn) // 建立CConn newconn.Run() } else { // error handling } }}func (conn *CConn) Run() { conn.onConnect() go func() { tickerRecv := time.NewTicker(time.Second * time.Duration(rateStatInterval)) for { select { case <- conn.StopChan: tickerRecv.Stop() return case <- tickerRecv.c: conn.packetRecv = 0 default: conn_closed := conn.parseAndHandlePdu() if conn_closed{ tickerRecv.Stop() return } } } }()}func (conn *CConn) onConnect() *User { user := &User{conn:conn, ... // 其他初始化內容}}
每個串連都用一個go協程來處理,這樣就能將每個串連都獨立起來,當然還需要注意一點,每個服務節點的串連數應該有限時策略。
2,拿來即用的單例模式
import "github.com/dropbox/godropbox/singleton"var singleSrv = singleton.NewSingleton(func() (interface{}, error) { cluster, _ := cache.GetRedisCluster("singlecache") return &SingleMsgProxy{ Cluster: cluster, MsgModel: msg.MsgModel, }, nil})
3,泛型
type MyInterface interface { Len() int Less(i, j int) bool Swap(i, j int)}func CustomSort(d MyInterface) { ...}
不管使用CustomeSort的d是什麼類型,只要按照介面的要求實現了Len() Less() Swap()就可以使用CustomSort函數。