谈谈网络编程(基于C++语言)

jopen 12年前
   <blockquote>     <p>本文针对的是 Windows、Linux 下基于 C++ 语言的网络编程</p>    </blockquote>    <p>        我从事的是企业级的软件开发,纵观当今的企业级软件,单机模型已经越来越少,更多的是C/S模型,目前 client 和 server 之间通信是通过 socket 技术来实现的。</p>    <p>        上面提到了 socket 技术,自然要学习 TCP/IP 协议,对于 TCP/IP 的理论,学习 Richard 的《<a href="/misc/goto?guid=4958340995124688786" target="_blank">TCP/IP 详解卷1:协议</a>》 我认为是不二的选择,这本书涵盖内容很多,如果对于只是实现C/S通信的网络库而言,仅需要了解其中介绍 UDP 和 TCP 的章节就好,扎实的理论基础会为你以后遇到网络传输中出现的问题给予很好的解释,也便于你解决这些问题。理论联系实现,还是 Richard 的《<a href="/misc/goto?guid=4958340995942005677" target="_blank">UNIX 网络编程卷1:套接口 API</a>》(俗称 UNP1),这本书我一直在看,但是还没看完,我认为这是网络编程的圣经,你掌握了这本书,基本也就掌握了<a href="/misc/goto?guid=4958340996739818524" target="_blank">网络编程</a>,甚至细枝末节也能覆盖到。</p>    <p style="text-align:center;"><img title="谈谈网络编程(基于 C++ 语言)" border="0" alt="谈谈网络编程(基于C++语言)" src="https://simg.open-open.com/show/2db5003cedb2fcee9c79b07fcc517f84.jpg" width="396" height="396" /></p>    <p><strong>        以下只涉及 TCP 协议</strong></p>    <p>        紧接着学习转为实践,想想网络通信的场景:一个 server 要对应成百上千..个客户,这样必须要考虑到 server 的处理能力。</p>    <p>        最简单的模型就是你用一个进程来处理所有的客户端连接,my god!你想想,在处理过程中如果有上百个连接同时请求服务,我们采用这种模式,首先下一个连接要等着上一个连接处理完(同步),这个在处理的连接还很有 可能阻塞在数据操作(I/O)上,这样处理连接的效率之差及客户端的响应之慢我想几乎没有人能忍受吧。</p>    <p>        好,为了提高效率,我们改进一下,对每一个客户连接产生一个线程(windows)或进程(linux)来处理,抛开线程或进程的上下文切换损耗不谈,也不谈 SMP,就单单看产生成千上百个线程和进程的可行性,对不起,咱操作系统可是有线程或进程资源上限的。</p>    <p>        为了解决线程频繁切换造成的资源损耗和资源数限制问题,我们再改进一下,采用一个线程池来处理部分连接,其他连接排队等候,毕竟咱 cpu 不多,同时也就能处理那么几个连接,响应效率和处理效率依然提不上去。</p>    <p>        想一个问题,其实我们的网络耗时一般都是在数据操作上(I/O),为了增加客户端的响应,我们可以把一次网络接入分为处理连接的线程和进行逻辑 处理的线程,这样就可以极大地提高客户端的响应,但是记住一定要在逻辑处理线程中维护住这个连接的会话。这样仿佛还不错,no,no,其实也不好,你并不 知道什么时候有数据到来需要处理,你必须要轮询来确定可不可以进行数据操作….,效率还是不好啊。</p>    <p>        好了,咱不自己独创技术了,选用经典的 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。</p>    <p>        谈一些我自己的看法:从我的理解上,对于大部分网络库而言,很多都是I/O密集型的,这样仿佛采用 Proactor 模式更有优势,但是 linux 下没有和 windows 下 IOCP 类似的机制,但是可以采用 epoll 加任务队列的方式实现一套,但是仿佛很复杂,我想自己实现就算了吧。好在“山穷水复疑无路,柳暗花明又一村”,boost asio 已经为我们封转好了 windows 和 linux 下的 Proactor 实现,windows 采用的是完成端口,linux 下采用的是 epoll 加任务队列的方式实现。下一步我准备把目前 linux 下采用 epoll 方式实现的 Reactor 网络库改为 boost asio 的实现。</p>    <p>        今天,对于网络编程先总体并且概括的介绍下吧,其实还有很多问题没有涉及,我本人对网络编程十分的感兴趣,现在也在从事这方面的工作,所以以后 有机会希望和大家一起分享一些更细致全面的知识,鉴于本人水平有限,希望大家能对文章中出现的错误给予批评指正,我们一起进步……</p>    <div id="come_from">    来自:     <a id="link_source2" href="/misc/goto?guid=4958340997530423152" target="_blank">51CTO</a>    </div>