chromedp是一个更快更简单的支持Chrome DevTools Protocol协议的Go库,它是目前最流行的headless浏览器库之一,你可以使用它做很多只能通过浏览器才能执行的任务,比如网页截屏、网页渲染测试、下载视频、模拟登录等,今天我介绍它的一个有用而且很简单的功能:为一个网页生成一个pdf格式的截屏,更多的例子你可以查看官方示例chromedp/examples。
chromedp是一个更快更简单的支持Chrome DevTools Protocol协议的Go库,它是目前最流行的headless浏览器库之一,你可以使用它做很多只能通过浏览器才能执行的任务,比如网页截屏、网页渲染测试、下载视频、模拟登录等,今天我介绍它的一个有用而且很简单的功能:为一个网页生成一个pdf格式的截屏,更多的例子你可以查看官方示例chromedp/examples。
当前, rpcx支持tcp、kcp、quic、unix domain、http、jsonrpc 2.0等传输协议,并没有考虑websocket的支持,原因在于考虑到微服务更多的是企业内部服务之间的通讯,不太可能暴露给浏览器,企业内部大多采用tcp的方式传输,或者udp族(kcp、quic)方式的传输,但是还是有用户提出希望能支持websocket。
我想websocket可能还是会有一些场景下使用,比如游戏开发,移动端核服务端的通讯等等,所以经过慎重考虑,我决定在 rpcx 1.6.2版本中增加对websocket的支持。
基于rpcx良好的架构设计,实现对websocket的支持并不难。
本来,rpcx对kcp、quic的支持也不复杂,原因在于rpcx的通讯采用的net.Conn的这样一个通用的接口,listent.Accept方法接受客户端的请求后返回一个net.Conn对象,后续请求的解析、处理,写回都是在这个通用接口上操作的,所以非常容易支持新的传输协议。
以前rpcx还支持其它的udp的扩展协议,比如
因为这两个协议用的人很少,所以在rpcx 1.6中把这两个协议的支持去掉了。
所以,对于websocket来说,找到一个可信赖的、合适的websocket库,可以很容易的实现基于websocket传输的微服务框架。
目前Go生态圈常用的websocket库如下:
虽然像gobwas/ws性能优良、gorilla/websocket功能齐全,但是考虑到API的便利性,我还是决定使用Go官方的x/net/websocket库,一来有官方背书,值得信赖,二来rpcx使用websocket功能比较简单,就是期望能获得一个net.Conn对象,x/net/websocket库正好能满足需求。
如果服务端采用websocket协议,那么network应该写成ws或者wss,而不是tcp或者quic。
服务端会启动一个http server处理websocket请求。 默认的websocket path为 share.DefaultRPCPath,只要服务端核客户端保持一致即可。
ServeWS会传入一个*websocket.Conn参数,它实现了net.Conn接口,所以后续的处理使用通用的s.serveConn(conn)即可。
1 |
|
服务端的改造就如此简单,接下来看看如何部署一个服务端的websocket服务:
1 | func main() { |
客户端最重要的是要实现一个websocket协议的建连,如果实现了这个方法,客户端的改造基本就完成了。这个方法的实现如下:
1 | func newDirectWSConn(c *Client, network, address string) (net.Conn, error) { |
在建立连接的时候为ws和wss协议调用这个方法即可:
1 | func (c *Client) Connect(network, address string) error { |
客户端改造完成后,我们写一个客户端调用改车把刚才启动的websocket服务:
1 | func main() { |
所以你看到,对于一个新的传输协议来说,如果它的连接能够遵循net.Conn接口,rpcx支持它还是很容易的。
完整的使用websocket传输协议的例子: websocket example。
我在二月份的文章利好!极大可能在go 1.17中就能尝试泛型提到,虽然Go泛型会在Go 1.18中正式发布,但是因为各种原因,代码已经开始在master分支中实现,所以极大可能你会在今年9月份发布的Go 1.17中就能尝试使用Go泛型。
那么,现在,可以去掉"可能"这两个字了。在Go 1.17可以确定的说你能够尝试Go泛型编程了,尽管建议你还是在Go 1.18以及以后的版本才正式在产品中使用泛型。
你也知道,Go 将在1.18 中正式支持泛型。依照Go每年发布两个版本的节奏,Go 1.18会在2022年春,也就是二月份左右发布,但是有可能你会在Go 1.17中尝鲜。
Go的泛型近一年来一直由Ian Lance Taylor(编译器大牛、Go核心成员)和Robert Griesemer(Go创始三巨头之一,Google V8、Chubby和HotSpot JVM的主要贡献者)等人开发,一直在dev.typeparams分支上做预研和开发工作。
Go编译的程序非常适合部署,如果没有通过CGO引用其它的库的话,我们一般编译出来的可执行二进制文件都是单个的文件,非常适合复制和部署。在实际使用中,除了二进制文件,可能还需要一些配置文件,或者静态文件,比如html模板、静态的图片、CSS、javascript等文件,如何这些文件也能打进到二进制文件中,那就太美妙,我们只需复制、按照单个的可执行文件即可。
一些开源的项目很久以前就开始做这方面的工作,比如gobuffalo/packr、markbates/pkger、rakyll/statik、knadh/stuffbin等等,但是不管怎么说这些都是第三方提供的功能,如果Go官方能内建支持就好了。2019末一个提案被提出issue#35950,期望Go官方编译器支持嵌入静态文件。后来Russ Cox专门写了一个设计文档Go command support for embedded static assets, 并最终实现了它。
Go 1.16中包含了go embed的功能,而且Go1.16基本在一个月左右的时间就会发布了,到时候你可以尝试使用它,如果你等不及了,你也可以下载Go 1.16beta1尝鲜。
本文将通过例子,详细介绍go embed的各个功能。
Go语言语法简单,学习起来容易,也容易上手,所以越来越多的公司和个人采用Go语言开发应用程序。不管使用什么语言,内存泄露是经常遇到的一类问题,而使用Go语言编写内存泄露的代码却不容易,本文将教你几招编写出内存泄露的代码,以满足你创造出内存泄露bug的心里需求。
即使你编写出内存泄露的bug,一般来说也很容易通过pprof查找出来,或者通过pprof的两次对比中找出哪一块出现的问题,所以不要因为写出bug就沾沾自喜,此类bug还是很容易被发现的。
Go标准库提供了便利的方法,可以很容易地运行外部命令,一般我们会使用os/exec包下的方法实现执行外部命令以及和外部命令交互。os/exec包装了os.StartProcess方法,更方便的进行输入和输出的访问,提供I/O pipe等功能。我会通过两篇文章专门介绍Go启动新进程,执行外部命令的方法,这是第一篇,专门介绍os/exec库。
稍微入门Go语言的程序员都知道,GOMAXPROCS变量可以限制并发运行用户态Go代码操作系统的最大线程数,你甚至可以通过调用函数func GOMAXPROCS(n int) int在程序运行时改变最大线程数的大小,但是当你进一步阅读文档,或者更深入的应用Go语言开发的时候,你就会发现,实际线程数要比你设置的这个数要大,有时候甚至远远大于你设置的数值,更悲剧的是,即使你的并发任务回退到没有几个的时候,这些线程数还没有降下来,白白浪费内存空间和CPU的调度。
我在极客时间上开了一门面向中高级Go程序员的课程:Go 并发编程实战课,有读者问Go channel中的实现中使用了mutex,这个mutex和标准库中的Mutex有什么不同?正好在百度厂内分享Go相关课程中有同事也提出了相同的问题,所以我专门写一篇文章介绍一下。