golang长连接和短连接的学习

匿名 (未验证) 提交于 2019-12-03 00:13:02
  • TCP连接示意图

  • 长连接和短链接的区别
    • 客户端和服务端响应的次数
      • 长连接:可以多次。
      • 短链接:一次。
    • 传输数据的方式
      • 长连接:连接--数据传输--保持连接
      • 短连接:连接--数据传输--关闭连接
  • 长连接和短链接的优缺点

    • 长连接
      • 优点
        • 省去较多的TCP建立和关闭的操作,从而节约时间。
        • 性能比较好。(因为客户端一直和服务端保持联系)
      • 缺点
        • 当客户端越来越多的时候,会让将服务器压垮。
        • 连接管理难。
        • 安全性差。(因为会一直保持着连接,可能会有些无良的客户端,随意发送数据等)
    • 短链接
      • 优点
        • 服务管理简单。存在的连接都是有效连接
      • 缺点
        • 请求频繁,在TCP的建立和关闭操作上浪费时间
  • 长连接和短连接使用情况举例

    • 长连接
      • 微信/qq
      • 一些游戏
    • 短连接
      • 普通的web网站
  • golang实现长连接参考代码(实现群聊天)

    server.go

package main  import(     "fmt"     "net"     "bufio"     "errors" ) var connSlice []*net.TCPConn  // 创建TCP长连接服务 func createTcp(){     tcpAdd,err:= net.ResolveTCPAddr("tcp","127.0.0.1:9999")  //解析tcp服务     if err!=nil{         fmt.Println("net.ResolveTCPAddr error:",err)         return     }     tcpListener,err:=net.ListenTCP("tcp",tcpAdd)   //监听指定TCP服务     if err!=nil{         fmt.Println("net.ListenTCP error:",err)         return     }     defer tcpListener.Close()     for{         tcpConn,err:=tcpListener.AcceptTCP() //阻塞,当有客户端连接时,才会运行下面         if err!=nil{             fmt.Println("tcpListener error :",err)             continue         }         fmt.Println("A client connected:",tcpConn.RemoteAddr().String())         boradcastMessage(tcpConn.RemoteAddr().String()+"进入房间"+"\n")  //当有一个客户端进来之时,广播某某进入房间         connSlice = append(connSlice,tcpConn)         // 监听到被访问时,开一个协程处理         go tcpPipe(tcpConn)     } }  // 对客户端作出反应 func tcpPipe(conn *net.TCPConn){     ipStr := conn.RemoteAddr().String()     fmt.Println("ipStr:",ipStr)     defer func(){         fmt.Println("disconnected:",ipStr)         conn.Close()         deleteConn(conn)         boradcastMessage(ipStr+"离开了房间"+"\n")     }()     reader:=bufio.NewReader(conn)     for{         message,err:=reader.ReadString('\n')  //读取直到输入中第一次发生 ‘\n’         //因为按强制退出的时候,他就先发送换行,然后在结束         if message == "\n"{             return         }         message = ipStr+"说:"+message         if err!=nil{             fmt.Println("topPipe:",err)             return         }         // 广播消息         fmt.Println(ipStr,"说:",message)         err = boradcastMessage(message)         if err!=nil{             fmt.Println(err)             return          }     } }  // 广播数据 func boradcastMessage(message string)error{     b := []byte(message)     for i:=0;i<len(connSlice);i++{         fmt.Println(connSlice[i])         _,err := connSlice[i].Write(b)         if err!=nil{             fmt.Println("发送给",connSlice[i].RemoteAddr().String(),"数据失败"+err.Error())             continue         }     }     return nil }  // 移除已经关闭的客户端 func deleteConn(conn *net.TCPConn)error{     if conn==nil{         fmt.Println("conn is nil")         return errors.New("conn is nil")     }     for i:= 0;i<len(connSlice);i++{         if(connSlice[i]==conn){             connSlice = append(connSlice[:i],connSlice[i+1:]...)             break         }     }     return nil }  func main(){     fmt.Println("服务端")     createTcp()     // data := []string{"a","b"}     // data = append(data[:1],data[2:]...)  //测试data[2:]...会不会因为超过范围报错     // fmt.Println(data) }
**client.go**
package main  import(     "os"     "fmt"     "net"     "bufio" )   // 客户端连接服务端 func createSocket(){     tcpAdd,err := net.ResolveTCPAddr("tcp","127.0.0.1:9999")  //解析服务端TCP地址     if err!=nil{         fmt.Println("net.ResolveTCPAddr error:",err)         return     }     conn,err := net.DialTCP("tcp",nil,tcpAdd)   //raddr是指远程地址,laddr是指本地地址,连接服务端     if err!=nil{         fmt.Println("net.DailTCP error:",err)         return     }     defer conn.Close()     fmt.Println("connected")     go onMessageRectived(conn)   //读取服务端广播的信息      for {         // 自己发送的信息         var data string         fmt.Scan(&data)         if data == "quit"{             break         }         b := []byte(data + "\n")         conn.Write(b)     } }  // 获取服务端发送来的信息 func onMessageRectived(conn *net.TCPConn){     reader := bufio.NewReader(conn)     for {         // var data string         msg,err := reader.ReadString('\n')  //读取直到输入中第一次发生 ‘\n’         fmt.Println(msg)         if err!=nil{             fmt.Println("err:",err)             os.Exit(1)    //服务端错误的时候,就将整个客户端关掉         }        } }  func main(){     fmt.Println("开启客户端")     createSocket() }
  • golang实现短连接参考代码

    server.go

package main  import (     "fmt"     "net/http" )  func main(){     fmt.Println("服务端")     http.HandleFunc("/PrintHello",PrintHello)     http.ListenAndServe(":8080",nil) }  func PrintHello(w http.ResponseWriter,r *http.Request){     data := "hello word"     fmt.Fprintf(w,data) } 

client.go

package main  import(     "fmt"     "net/http"     "io/ioutil" )  func main(){     fmt.Println("客户端")     res,err:=http.Get("http://localhost:8080/PrintHello")     if err!=nil{         fmt.Println(err)         return     }     defer res.Body.Close()     data,err := ioutil.ReadAll(res.Body)     if err!=nil{         fmt.Println(err)         return     }     fmt.Println("接受服务端发送数据:",string(data)) } 
  • 另外,golang的client实现长连接的方式是通过于服务端在建立连接之后保持连接

  • 写的不对的地方,希望可以加微信讨论一下

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!