分享
  1. 首页
  2. 文章

golang 网络通信

bradyjoestar · · 6806 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。


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

reference links


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:bradyjoestar

查看原文:golang 网络通信

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
6806 次点击
上一篇:webserver
下一篇:golang runtime
1 回复 | 直到 2017年12月06日 03:22:59
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏