看到这个标题,肯定有同学会纳闷:tcp本来不就是全双工的么,https是在tcp层之上的,怎么还会单独拎出这个来说?没错,tcp是全双工的,但openssl的实现,不代表你能像普通socket一样在收发两个通道上随意操作。
要点1:OpenSSL并发读写,是不安全的
其实OpenSSL官方的文档上还没找到直接的话术指明同一个SSL不能两个线程并发读写,但实际上,外网上、km上都有文章说在多线程并发情况下读写会引起程序崩溃。想来是SSL对象内部实现中,维护了共享的状态变量或者缓存区之类的资源,并发读写时会改坏数据导致崩溃。可以通过初始化时设置加锁回调的方式来避免(http://linux.die.net/man/3/crypto_set_locking_callback),但锁终究对性能有不小的影响。
不过gaps现有的实现是单进程的,即单进程中通过epoll完成了多个机器人连接的收发数据,所以并不存在多线程并发的问题,也无需加锁。由此,小标题的“全双工实现”其实更严格说是”单进程情况下读写互不干扰的双工实现“。
要点2:OpenSSL的建链、收包、发包接口,其是否阻塞都随socket本身属性而变,所以OpenSSL可以非阻塞使用
在我们的场景下,用epoll来维护机器人的并发建连接和收发包,当然希望任何一个动作都是非阻塞的,这样才能将多路复用的功效发挥到极致。那现在加了个ssl2进去,是否还能保持这一点?答案是能。所以,这里的要点是,OpenSSL的建立连接、收包、发包,都可以是非阻塞的。
建立连接不用上图中的SSL_connect,而用SSL_do_handshake。这样,如果socket本身设置为非阻塞的,那这个操作也就不会阻塞,而是有三种返回可能: