golang socket伺服器

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

一、main.go該代碼從項目中分離出來,自行修改後再運行)

package mainimport ("flag""fmt""log""os""runtime")var (Port           = flag.String("i", ":12345", "IP port to listen on")logFileName    = flag.String("log", "cServer.log", "Log file name")configFileName = flag.String("configfile", "config.ini", "General configuration file"))var (configFile = flag.String("configfile", "config.ini", "General configuration file"))func main() {runtime.GOMAXPROCS(runtime.NumCPU())flag.Parse()//set logfile StdoutlogFile, logErr := os.OpenFile(*logFileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666)if logErr != nil {fmt.Println("Fail to find", *logFile, "cServer start Failed")os.Exit(1)}log.SetOutput(logFile)log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)//set logfile Stdout End//start listenlistenErr := StartListen(*Port)if listenErr != nil {log.Fatalf("Server abort! Cause:%v \n", listenErr)}}

二、listener.go該代碼從項目中分離出來,自行修改後再運行)

package mainimport ("code.google.com/p/go-uuid/uuid""errors""fmt""goCS/consistent""log""net""sync""time")const (ConnectionMax = 100 //CS max connect)//conn Pool infovar (poolLock sync.RWMutexpoolCli  [ConnectionMax]*CliInfo)//Web user infotype UserInfo struct {WS_ID       intWS_Name     stringServiceName string}//Cli infotype CliInfo struct {AssignID   int            //cs assign IDConn       net.Conn       // The TCP/IP connectin to the player.ConnTime   time.Time      //連線時間VerifyKey  string         //串連驗證KEYConnVerify bool           //是否驗證ServerType int32          //伺服器類型(1DB伺服器,2WEB伺服器)NodeStat   int32          //伺服器目前狀態(0、宕機;1、正常;2、資料匯入中;3、準備中;4、資料遷出中Address    string         //服務地址Port       int            //服務連接埠BackupSer  map[string]int //備份伺服器列表map(ip:port)sync.RWMutex}type hashPool struct {Version  intCircle   map[uint32]string //hash圈節點分布Replicas map[string]int    //hash圈節點範圍}var SerHashPool *consistent.Consistent = consistent.New()// Client disconnectfunc (cli *CliInfo) disconnect(clientID int) {poolLock.Lock()defer poolLock.Unlock()cli.Conn.Close()log.Printf("Client: %s quit\n", cli.VerifyKey)if cli.ServerType == 1 {//掉線處理if ok := cli.removeDBS(); ok {poolCli[clientID] = nil}} else {}}//listen handlefunc (cli *CliInfo) listenHandle(clientID int) {headBuff := make([]byte, 12) // set read stream sizedefer cli.Conn.Close()//send verify Key:b := []byte(cli.VerifyKey)cli.Conn.Write(b)// fmt.Println("cli-IP:", cli.Conn.RemoteAddr().String())//await 10 second verifycli.Conn.SetDeadline(time.Now().Add(time.Duration(10) * time.Second))forControl := truefor forControl {var headNum intfor headNum < cap(headBuff) {readHeadNum, readHeadErr := cli.Conn.Read(headBuff[headNum:])if readHeadErr != nil {log.Println("errHead:", readHeadErr)forControl = falsebreak}headNum += readHeadNum}if headNum == cap(headBuff) {//pack head HandlepackHead := packHeadAnalysis(headBuff)bodyBuff := make([]byte, packHead.PackLen)var bodyNum intfor bodyNum < cap(bodyBuff) {readBodyNum, readBodyErr := cli.Conn.Read(bodyBuff[bodyNum:])if readBodyErr != nil {log.Println("errBody:", readBodyErr)forControl = falsebreak}bodyNum += readBodyNum}if bodyNum == int(packHead.PackLen) {//pack body Handlecli.packBodyAnalysis(clientID, packHead, bodyBuff)// fmt.Printf("packType:%d;packOther:%d;packLen:%d\n", packHead.PackType, packHead.PackOther, packHead.PackLen)}}}cli.disconnect(clientID)}//Check or assign new connfunc NewConnection_CS(conn net.Conn) (ok bool, index int, info *CliInfo) {poolLock.Lock()defer poolLock.Unlock()//Assign ID for clientvar i intfor i = 0; i < ConnectionMax; i++ {if poolCli[i] == nil {break}}//Too many connectionsif i > ConnectionMax {log.Printf("Too many connections! Active Denial %s\n", conn.RemoteAddr().String())conn.Close()return false, 0, nil}//Create client base infoCli := new(CliInfo)Cli.Conn = connCli.ConnTime = time.Now()Cli.VerifyKey = uuid.New()Cli.BackupSer = make(map[string]int)//Update Pool infopoolCli[i] = Clilog.Println("Cli ID assign ok:", i)return true, i, Cli}//start listensfunc StartListen(addr string) error {listener, err := net.Listen("tcp", addr)if err != nil {return err}// if Errors accept arrive 100 .listener stop.for failures := 0; failures < 100; {conn, listenErr := listener.Accept()if listenErr != nil {log.Printf("number:%d,failed listening:%v\n", failures, listenErr)failures++}if ok, index, Cli := NewConnection_CS(conn); ok {// A new connection is established. Spawn a new gorouting to handle that Client.go Cli.listenHandle(index)}}return errors.New("Too many listener.Accept() errors,listener stop")}

三、原理

一個新的串連建立。產生一個新的gorouting來處理用戶端。

    一個用戶端進來首先分配一個唯一ID,並初始化該用戶端的基本資料(見:NewConnection_CS方法),產生一個新的gorouting來處理用戶端。

    如果伺服器達到設定的串連上限,將拋棄該用戶端。

    用戶端串連(分配ID)正常後,將等待10秒來給用戶端進行驗證超期將斷開該用戶端串連(見:listenHandle中的cli.Conn.SetDeadline)。

    驗證成功後,開接與使用者資料進行分析處理:接收原理為:前4位元組為包類型,4-12位元組為包長,首先接收夠12位元組後進行包頭解析(如不夠12位元組將進行等待直到夠12位元組),解析出4-12位元組來得到整個包體的長度進行讀取(如不夠將等待直到夠包體長度)

    整包讀取完後,根據0-4位元組判斷包的類型進行包的處理。

四、伺服器串連出錯達到100條後將終止運行

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.