开了个新坑 ezio

前段时间分别在 Linux 和 Windows 下实现了一个简单的 TCP 网络框架之后,感觉一些必要的坑都踩的差不多了,可以开始动手写一个真正的跨平台的 TCP 网络框架了。

于是就有了这个新坑:ezio。

ezio 这个名字是某天跑步的时候突然想到的,有几重含义:

  • 致敬刺客信条里的 Ezio Auditore,寓意希望这个库能够和刺客一样,虽轻量,但需要时恰到好处,不含糊
  • 致敬(碰瓷)Boost.ASIO,因为两个名字发音非常接近
  • 第三个是朋友发现的,他把 ezio 念成了 e-z-io(easy io),于是赋予了一个新的含义

ezio 的目标是:提供同时支持 Linux 和 Windows 的轻量型非阻塞且具备扩展性(non-blocking and scalable)的 TCP 网络框架;针对 Linux 做性能侧优化,针对 Windows 做一致性开发体验的优化。

这个目标初看起来有点怪异,但是确实非常实际的做法。

因为 Linux 和 Windows 在网络编程上存在根本的范式差异性,所以为了提供一致的对外接口,必须要有所侧重和牺牲。Linux 目前占据了绝大多数互联网产品服务器系统的份额,而 Windows 则提供了可以说是当前最好的开发环境。

ezio 这个设计目标可以使得绝大多数业务逻辑在 Windows 上开发,然后在 Linux 上进行最后的部署。

Read More

Dealing With Multiple Types As a Category

Macro ENSURE() from KBase can ‘capture’ variables by outputing their content to the internal stringtream, provided the type of captured variables has overloaded operator<<().

Read More

Monthly Read Posts in July 2018

Programming Language

Clearer interfaces with optional

Partial queries with optional

optional<T> 介绍 & 简单使用例子


CppCon 2015: John R. Bandela “Simple, Extensible Pattern Matching in C++14”

一个轻量级的 pattern matching 库简要介绍。


CppCon 2015: Greg Miller “Time Programming Fundamentals”

Google 内部实现的一个处理 date-time 的轮子。

不过讲道理,这块内容还不如关注一下之前 monthly read posts 里出现的这篇 里提到的 date library。

看起来差不多会在 C++ 20 引入


When MSDN says NULL, is it okay to use nullptr?

Short anwser: YES.

Read More

在 Windows 上运行 Linux GUI 程序

自从 Windows 10 提供 WSL 之后,在 Windows 上运行 Linux CLI 程序并不是一个复杂的事情;然而俗话说饱暖思淫欲,既然可以做到在 Windows 上跑 Linux CLI 了,下一步自然想的是在 Windows 上跑 Linux GUI 程序。

之所以要跑 GUI 是因为,无论是 vscode 还是 CLion,写 C++ 的体验都比在 terminal 里开一个 vim 要好太多了,无论你是花了多少时间配置了 .vimrc,在 CLion 面前都是战五渣。更何况我买了 Jetbrains 的 All product license,不用用难道留着过年吗。

这里先解答两个常见疑问:

Q:为什么不直接在虚拟机里使用?
A:因为 Linux 对 4K 屏原生支持太糟糕。哪怕 Mint 提供了 double scaling,解决了一些外观上的问题,我在 4K 的环境下一开 vscode 程序就崩溃,而且运行操作明显掉帧。
另外一个问题是,单纯的虚拟机操作和外界宿主太隔离,等于我得配置两套完全一样的环境(比如浏览器,常见的应用,甚至 SS 等),而且和宿主的交互非常不够便利。

Q:为什么不买 macbook?
A:??你是认真的么?OS X 那么垃圾的系统。再说我要写 C++ server-end 的代码,要是可以用 OS X 我为什么不直接在 Windows 上跑?

另外有一个剧透:我尝试过运行 WSL 里的 Linux GUI 程序,例如 CLion,但是目前 WSL 的文件系统性能过于糟糕,CLion 一个劲的冒错误提示,所以,下面的环境假定是虚拟机里的 Linux 或者一台单独的 Linux 设备。

Read More

Monthly Read Posts in Jun 2018

Programming Language

CppCon 2015: Richard Powell “Intro to the C++ Object Model”

基本覆盖了 POD,无需函数类,单继承的情况,扫盲效果俱佳。

至于为什么没有包含 multiple inheritance / virtual inheritance,作者说自己不是很 condifent with that。

讲道理,MI / VI 在一般的设计里都会尽量避免,而且各种乱七八糟的 case 很多,这里不涉及反而是个正确的做法。


Assertions

首先,我很赞同文中作者对于 assertion 是 guarantees given by the author of a piece of code to himself/herself 但是接下来的大部观点都不赞同。

比如作者认为不应该 assert on precodintions & postconditions,因为 assertion 是 for implementation details,这个思路其实不对。

关于 assertion,目前看过最好的阐述还是 Writing Solid Code,推荐去阅读这个。


Compile-time computations

这篇 post 展示了 constexpr functions 错误报告的常见手段:抛异常。

这个在之前的某个 cppcon talk 里有专门的介绍。

另外,文中更进一步,抽出专门的 constexpr validation functions,并通过 comma operator 串联。

C++ 14 支持多句之后,连 comma operatos 都可以免掉了。


Read More

Modern CMake

但凡有点历史的东西,在演进到一个新的阶段时,总会总结一套新的 practices 然后冠之以 modern,例如 modern C++,还有今天的主题 —— modern CMake。

上周花了一点时间稍微研究了一下所谓的 modern cmake,然后将 KBase 在 POSIX 上的 cmake 文件都按照 modern cmake 的做法做了修改,结果可见

Read More

Build Your Own HTTP Proxy Server Using Go

Go is a quite awesome programming language for building network applications. So I built my own HTTP proxy server using go last week.

To grasp the essence of how HTTP proxy server works, I choosed to implement it on TCP transport layer, forwarding TCP traffic directly.

Essentially, it runs a server, accepting incoming TCP connections and from which the server extracts target host of a request by parsing HTTP protocol messages. The server then establishes a connection to the target host, and finally operates as an intermedia, forwarding traffic from one host to another.

Implementing a TCP server which is able to handle concurrent requests uing go is easier than you thought: just runs a loop to accept requests, launching a new goroutine for each new connection:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
type Server struct {
addr string
listener net.Listener
}

func (srv *Server) Start() {
var err error
srv.listener, err = net.Listen("tcp", srv.addr)
if err != nil {
log.Fatalf("Failed to listen at %s : %v", srv.addr, err)
}

log.Printf("Proxy is listening at %s", srv.addr)

srv.runLoop()
}

func (srv *Server) runLoop() {
for {
conn, err := srv.listener.Accept()
if err != nil {
log.Printf("Failed to accept an incoming connection : %v", err)
continue
}

go srv.handleConnection(conn)
}
}

func (srv *Server) handleConnection(conn net.Conn) {
c := newConnection(conn)
c.serve()
}

Read More