COW
https://github.com/cyfdecyf/cow/
去年 8 月开始写这个 HTTP 代理的时候是作为 Go 的练手项目的,现在已经是我日常使用的一个工具了。
这个代理主要用处是辅助自动化翻墙。机制很简单,默认对 client 请求使用直接连接,遇到 connection reset 或者 dial/read timeout 就用翻墙代理重试请求。更多机制有兴趣的同学可以看下 github 上的 readme。
下面说下写这个代理过程中的一些感受吧。
一些使用 Go 的时候最让觉得舒服的地方:
- 标准库很好用
- 跨平台支持、交叉编译很方便
- 个人比较喜欢多值返回的方式来处理错误
- go tool 极大的方便了编译、测试等工作
- 静态链接方便二进制文件的发布
偶尔也会有发现一些不太令人满意的地方:
- 没有泛型有时是会有些不便,例如我想实现一个通用的 set,如果用 interface{} 作为 value 的类型则没有编译时类型检查
- 关于这个问题 Russ Cox 说过他们考虑过,但是还没有找到合适的方式,期待某一天出现
- cgo 调用 blocked call 可能会需要创建新线程,目前不会限制创建线程的数量
- 这个问题目前也在考虑解决中
- 感谢 minux 让我明白了这个问题
- 从这个问题里学到的是用带有 runtime 的语言,好好了解 runtime 还是必须的
- 有些标准库 (例如 strconv) 只处理 string 而不处理 []byte,所以不得不做转换而引入一些不必要的 copy
- 在写 COW 的时候我特地从 strconv 里拷贝了 ParseInt 的代码来专门处理 []byte
- 这个是有点 micro optimization 了,不过问题还是存在的,Brad Fitzpatrick 也创建过 issue
- net 包返回的错误难以判断具体是什么错误
- 今天想到发这个贴就是因为又看到之前有人问如何判断 connection reset 错误的帖子
- 像 use of closed network connection 这个错误除了用 Error() 然后判断字符串是否匹配以外貌似没有其他办法
- connection reset, timeout, dns error 这些错误在 unix 和 windows 平台要用不同的方式去判断
总体来说,这些不太令人满意的地方都不是太大的问题,或者是已经在解决中。
写这个代理服务器的过程中慢慢体会到 Go is not meant to innovate programming theory. It’s meant to innovate programming practice. 这句话的含义。
越来越喜欢 Go,她已是我的最喜欢用的编程语言。