内容简介:go-shadowsocks是一个非常好的学习golang网络编程的例子。在本篇博文中重点阐述golang网络通信几个各种不同协议下服务端和客户端的实现。网络通信协议主要有以下两种外加一种增加的协议
title: golang 网络编程
golang 网络编程
go-shadowsocks是一个非常好的学习golang网络编程的例子。在本篇博文中重点
阐述golang网络通信几个各种不同协议下服务端和客户端的实现。
网络通信协议主要有以下两种外加一种增加的协议
- golang tcp
- golang upd
- golang kcp:在upd上进行增强的协议,KCP 是一个快速可靠协议,能以比 TCP浪费10%-20%的带宽的代价,换取平均延迟降低 30%-40%,且最大延迟降低三倍的传输效果。
golang的一大优势就是多核、并行、网络编程。通过goroutine与channel可以很方便地协程,协程比线程更轻量级,占用资源更小,可以更好地适用与并行计算。
下面对这三种分别进行说明。
golang tcp
下面根据两种golang tcp server和client的例子进行说明
单connection的tcp server与client 端
tcp server
package main import ( "net" "fmt" ) func main(){ // tcp 监听并接受端口 l, err := net.Listen("tcp", "127.0.0.1:65535") if err != nil { fmt.Println(err) return } //最后关闭 defer l.Close() fmt.Println("tcp服务端开始监听65535端口...") // 使用循环一直接受连接 for { fmt.Println("loop test") //Listener.Accept() 接受连接 //conn 是双方的。和长度为1的channel有些类似。 c, err := l.Accept() if err!= nil { return } //处理tcp请求 go handleConnection(c) } } func handleConnection(c net.Conn) { //一些代码逻辑... fmt.Println("tcp服务端开始处理请求...") //读取 buffer := make([]byte, 1024) //如果客户端无数据则会阻塞,服务端阻塞,直到等待客户端传递数据。 c.Read(buffer) //服务端成功从阻塞状态走出,读取客户端的数据,并根据自身的接口输出buffer c.Write(buffer) fmt.Println("tcp服务端开始处理请求完毕...") }
tcp client
package main import ( "net" "fmt" ) func main() { //net.dial 拨号 获取tcp连接 conn, err := net.Dial("tcp", "127.0.0.1:65535") if err != nil { fmt.Println(err) return } fmt.Println("获取127.0.0.1:65535的tcp连接成功...") defer conn.Close() //客户端这里不用使用协程。使用协程的话main函数退出,所有 go 协程全部死掉。 conn.Write([]byte("echo data to server ,then to client!!!")) fmt.Println("test server") //读取到buffer buffer := make([]byte, 1024) //如果服务端没有把数据传递过来,那么客户端阻塞,直到服务端向其中写入了数据。 conn.Read(buffer) fmt.Println(string(buffer)) }
net utils
- net.Dial(客户端调用,拨号)
- net.Listen(服务端调用,监听接口)
- TCPListener.Accept(服务端调用,接受,创建连接。)
- conn.Read(客户端服务端都会调用,读取conn中数据)
- conn.write(客户端服务端都会调用,读取conn中数据)
其它net 提供的函数可以查看API
为了能够让服务端处理多个连接,使用了协程来处理来自多个客户端的连接请求。
客户端的实现没有用到协程。
另外tcp server的for函数非常有趣,在上面的测试例子中不会无限打印 loop test
,说明存在阻塞。只有每次有新连接过来才会放开。
双connection的tcp server与client 端
在上面的例子中,存在着以下的问题:
- server与client之间只存在一条连接。可能会出现这样的情况:服务器需要向客户端推送一些数据。而客户端建立的连接正处于block状态。
- server与client建立的连接是短连接。
存在的解决方法如下
- 在client的实现上增加 server模块,监听来自于服务器的请求,并进行处理。
- 在server与client另外新建立一条长连接。通过setKeepLive来保活。
- 使用channel,保证客户端的协程不会死掉。
golang udp
udp 的通信无需创建lister,直接进行数据的传输。
udp server
package main import ( "fmt" "net" ) func main() { // 创建监听 socket, err := net.ListenUDP("udp4", &net.UDPAddr{ IP: net.IPv4(127,0,0,1), Port: 23452, }) if err != nil { fmt.Println("监听失败!", err) return } fmt.Println("监听成功") defer socket.Close() for { // 读取数据 data := make([]byte, 4096) read, remoteAddr, err := socket.ReadFromUDP(data) if err != nil { fmt.Println("读取数据失败!", err) continue } fmt.Println(read, remoteAddr) fmt.Printf("%s\n\n", data) // 发送数据 senddata := []byte("hello client!") _, err = socket.WriteToUDP(senddata, remoteAddr) if err != nil { return fmt.Println("发送数据失败!", err) } } }
udp client
package main import ( "fmt" "net" ) func main() { // 创建连接 socket, err := net.DialUDP("udp4", nil, &net.UDPAddr{ IP: net.IPv4(127,0,0,1), Port: 23452, }) if err != nil { fmt.Println("连接失败!", err) return } defer socket.Close() // 发送数据 senddata := []byte("hello server!") _, err = socket.Write(senddata) if err != nil { fmt.Println("发送数据失败!", err) return } // 接收数据 data := make([]byte, 4096) read, remoteAddr, err := socket.ReadFromUDP(data) if err != nil { fmt.Println("读取数据失败!", err) return } fmt.Println(read, remoteAddr) fmt.Printf("%s\n", data) }
上面的server和client实现比较简单了,基本上没有什么要说的了。
golang kcp
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
如何把事情做到最好
乔治·伦纳德 / 张乐 / 中国青年出版社 / 2014-2 / 29.90元
•改变全球9800万人的人生指导书 •全美第一本系统阐述学习与成功之道的经典著作 •长期盘踞全美畅销书榜单 •21年后,这本传奇之书终于在中国震撼上市 •把事情做到最好,第一不强求天赋,第二不介意起步的早晚,你要做的就是“起步走”并“不停地走” 《如何把事情做到最好》出 版于1992年,经久不衰,经过一代又一代的读者口碑相传后,畅销至今。作者以其独特的视角告诉人们,如......一起来看看 《如何把事情做到最好》 这本书的介绍吧!