- 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实现长连接的方式是通过于服务端在建立连接之后保持连接
写的不对的地方,希望可以加微信讨论一下
来源:博客园
作者:Myuniverse
链接:https://www.cnblogs.com/MyUniverse/p/11621169.html