上一篇文章《TCP/IP协议分析》讲述了本身是如何和网络领域的开发扯上关系的。正如从招聘网站上抽出的几个关键词“TCP/IP, Socket, 多线程”可见,协议分析并非网络开发的主流,一般咱们所说的网络编程是socket编程。今天就以个人经从来讲一下socket编程的相关知识。html
socket编程的基础知识我就不在这里科普了,你们能够经过相关书籍和资料去了解。
python
在招聘工程师时面试问到某些新人这个问题。他们觉得会编写客户端/服务端创建链接正常收发数据的流程就认为本身了解socket开发。真是这样简单调用几个API,理解下三次握手,会使用bind、listen、......就能够了吗?linux
固然不是,随着客户端数量的增长,少许并发——>大量并发——>海量并发的过程当中服务端的处理难度也会随之增长。在服务端编程中很是有名的C10K问题(网络服务在处理数以万计的客户端链接时,每每出现效率低下甚至彻底瘫痪)就向咱们作了很详细的说明。可是客户端socket编程虽然没有这种并发要求就必定简单吗?我认为不是的。请参看个人这篇文章《客户端网络库实现真的很简单吗》。另外互联网中各类复杂的网络环境也会给咱们进行socket编程带来不少困难和挑战。git
因此整体来讲想要作好socket编程仍是有必定难度的。你们很容易从各类招聘渠道了解到精通这个领域的人在市场上很热销,报酬也很可观,并且多为一些互联网巨头和新兴互联网公司所须要。github
要想处理咱们上面所说的C10K甚至C100K问题,网络模型的选择是很是重要的。那么咱们首先要清楚几个概念:阻塞I/O,非阻塞I/O,I/O复用,异步I/O 。网络上关于这个话题的讨论有不少,我说说个人理解吧:面试
阻塞/非阻塞:进程/线程要访问的数据是否就绪,进程/线程是否须要睡眠等待。编程
同步/异步:访问数据的方式,同步须要主动读写数据,在读写数据的过程当中仍是会阻塞。异步只须要获得I/O操做完成的通知,并不主动读写数据,而是由操做系统去完成数据的读写。json
因此能够看出阻塞I/O,非阻塞I/O,I/O复用都属于同步的范畴。windows
常见的几种服务端网络模型:设计模式
all connections one thread+blocking I/O:服务端对全部客户端链接只用一个线程去处理。并且网络I/O仍是阻塞的。这在多并发状况下就是找死,吞吐率会很低,延迟会很是大。
per connection per thread+blocking I/O:服务端线程资源是有限的,并且线程的上下文切换是很耗资源的,随着客户端并发链接的增多系统资源也会慢慢吃紧。可是在这种模型的基础上,有些语言内置的协程(用户级线程)却能够解决资源问题。好比Go routine, Erlang actor。前几天刚发现了一个基于C语言的协程库state thread也能够用来实现用户级线程。
thread pool+blocking I/O:线程池的方式依然会受制于服务器CPU个数,天然也不会高效的。
non-blocking I/O + I/O multiplexing:网络I/O的多路复用,正是解决C10K问题最基础的方案。可是还能够进一步优化吗?
non-blocking I/O + I/O multiplexing + asyc I/O:很是理想、高效的网络模型。windows下是利用完成端口来帮咱们实现这个模型,linux下要依赖异步I/O机制,可是到底是否好用我没尝试过。
从上面又引出了两种高性能的服务端网络编程设计模式:基于I/O事件驱动的Reactor和基于异步I/O驱动的Proactor。其中non-blocking I/O + I/O multiplexing属于Reactor模式。non-blocking I/O + I/O multiplexing + asyc I/O属于Proactor模式。
今天咱们所讲的只基于linux平台。毕竟linux平台的服务器占据了市场份额的90%以上。linux下目前最成熟的模型是epoll。(说到这给你们提个问题:epoll和它的老前辈select有什么不一样呢?)
刚才讲到non-blocking I/O + I/O multiplexing时,提到过在此模型的基础上咱们还能够优化吗?能够的。咱们能够采用一个线程对应一个事件循环的机制启用多个线程。毕竟如今的服务器硬件资源是很强大的,咱们不要浪费了多cpu资源。这就引出了咱们要讲的另外一个概念:master—worker模型。字面上的理解就是有一个master负责协调工做,由好几个worker去实际完成工做。在这种编程模型中:也就是有一个master负责将客户端链接分发给不一样的worker线程,或者通知链接来了由worker去抢占,实际上由worker去完成客户端链接的读写或逻辑处理工做。这样不但有效利用了服务器的CPU资源,也增长了服务端的吞吐量,下降了客户端的延迟。更详细的讲解请参见个人文章《从master-worker模型看团队管理》 。
站在巨人的肩膀上可让咱们看得更为高远,若是选用了合适的第三方网络库也会使咱们的工做事半功倍。
ACE学之者生用之者死。这是陈硕老师对ACE库的评价,我以为很形象。对于学院派理想化的东西去学习收益很大,可是使用就不见得适合本身。
boost asio:has a “near STL” status;
Poco: 很全面的库不只仅有网络库。
libev :速度更快,bug更少,特性更多,体积更小;
libevent:简单,强大;
网络编程中还有很重要的一点是客户端/服务端交互数据协议的选择。咱们选择的依据有哪些呢?
网络数据大小——占用带宽,传输效率;
网络数据安全性——敏感数据的网络安全;
编码复杂度——序列化和反序列化复杂度,效率,数据结构的可扩展性,可 维护性;
协议通用性——大众规范;
咱们能够以自定义的角度采用TLV结构的二进制协议
能够以提供序列化和反序列化库的的角度采用第三方协议:protocol buffers, json, thrift
能够以选择文本化协议的角度选择xml,json协议。
个人理解是什么呢?请参见文章《网络传输数据格式的选择》。
关键词MTU、SO_LINGER、TCPNODELAY、TIMEWAIT、keepalive、串话...这些关键词都表明了某种你须要考虑和处理的网络状况。
辅助工具python、netcat、tcpdump、wireshark...它们都会成为使你事半功倍的巨人。
《UNIX网络编程卷1》
《Linux多线程服务端编程》
《构建高性能Web站点》
《UNIX网络编程卷1》
《Linux多线程服务端编程》
http://stackoverflow.com/questions/992069/ace-vs-boost-vs-pocohttp://stackoverflow.com/questions/9433864/whats-the-difference-between-libev-and-libevent