(本文针对的是windows,linux下基于c++语言的网络编程)
我从事的是企业级的软件开发,纵观当今的企业级软件,单机模型已经越来越少,更多的是C/S模型,目前client和server之间通信是通过socket技术来实现的。
上面提到了socket技术,自然要学习TCP/IP协议,对于TCP/IP的理论,学习Richard的
《TCP/IP详解 卷1:协议》我认为是不二的选择,这本书涵盖内容很多,如果对于只是实现C/S通信的网络库而言,仅需要了解其中介绍UDP和TCP的章节就好,扎实的理论基础会为你以后遇到网络传输中出现的问题给予很好的解释,也便于你解决这些问题。理论联系实现,还是Richard的
《UNIX网络编程 卷1:套接口API》(俗称UNP1),这本书我一直在看,但是还没看完,我认为这是网络编程的圣经,你掌握了这本书,基本也就掌握了网络编程,甚至细枝末节也能覆盖到。
(以下只涉及TCP协议)
紧接着学习转为实践,想想网络通信的场景:一个server要对应成千上万,甚至十万..个客户,这样必须要考虑到server的处理能力。
最简单的模型就是你用
一个进程来处理所有的客户端连接,my god!你想想,在处理过程中如果有上百个连接同时请求服务,我们采用这种模式,首先下一个连接要等着上一个连接处理完(同步),这个在处理的连接还很有可能阻塞在数据操作(I/O)上,这样处理连接的效率之差及客户端的响应之慢我想几乎没有人能忍受吧。
好,为了提高效率,我们改进一下,
对每一个客户连接产生一个线程(windows)或进程(linux)来处理,抛开线程或进程的上下文切换损耗不谈,也不谈SMP,就单单看产生成千上百个线程和进程的可行性,对不起,咱操作系统可是有线程或进程资源上限的。
为了解决线程频繁切换造成的资源损耗和资源数限制问题,
我们再改进一下,采用一个线程池来处理部分连接,其他连接排队等候,毕竟咱cpu不多,同时也就能处理那么几个连接,响应效率和处理效率依然提不上去。
想一个问题,其实我们的网络耗时一般都是在数据操作上(I/O),为了增加客户端的响应,
我们可以把一次网络接入分为处理连接的线程和进行逻辑处理的线程,这样就可以极大地提高客户端的响应,但是记住一定要在逻辑处理线程中维护住这个连接的会话。这样仿佛还不错,no,no,其实也不好,你并不知道什么时候有数据到来需要处理,你必须要轮询来确定可不可以进行数据操作....,效率还是不好啊。
好了,咱不自己独创技术了,
选用经典的Reactor和Proactor并发编程模式,他们都是基于事件驱动的,咱呢就是把网络中需要处理的事件注册到事件管理器中去(比如网络行为事件,IO操作事件.....),然后等事件状态就绪了,他就用回调的方式通知咱去处理,怎么样,这样至少CPU不会闲着了,只用一个线程就可以处理几乎所有的事件了。但是Reactor和Proactor还是有很大区别的,Reactor对于I/O这一步是需要自己处理的,但是Proactor对于I/O这一步是由操作系统完成的,然后把完成事件通知你,然后你就可以进行下一步操作了(比如从缓冲区buf里读数据),比自己操作I/O这种方式快多了吧。目前,我在windows下写网络库采用的是Proactor模式:用windows自己提供的完成端口模型(
IOCP)实现,在linux下,由于linux没有很好的异步I/O机制,只好采用Reactor方式了:使用的是linux特有的
epoll。谈一些我自己的看法:从我的理解上,对于大部分网络库而言,很多都是I/O密集型的,这样仿佛采用Proactor模式更有优势,但是linux下没有和windows下IOCP类似的机制,但是可以采用epoll加任务队列的方式实现一套,但是仿佛很复杂,我想自己实现就算了吧。好在“山穷水复疑无路,柳暗花明又一村”,boost asio 已经为我们封转好了windows和linux下的Proactor实现,windows采用的是完成端口,linux下采用的是epoll加任务队列的方式实现。下一步我准备把目前linux下采用epoll方式实现的Reactor网络库改为boost asio的实现。
今天,对于网络编程先总体并且概括的介绍下吧,其实还有很多问题没有涉及,我本人对网络编程十分的感兴趣,现在也在从事这方面的工作,所以以后有机会希望和大家一起分享一些更细致全面的知识,鉴于本人水平有限,希望大家能对文章中出现的错误给予批评指正,我们一起进步......
本文转自永远的朋友博客51CTO博客,原文链接http://blog.51cto.com/yaocoder/870553如需转载请自行联系原作者
yaocoder