C++ windows网络编程系列1—各种通信模型对比

来源:互联网 发布:麦迪62分数据 编辑:程序博客网 时间:2024/05/18 19:44

前言:

作为一名C++编程的还算比较新的司机,已经工作了两年多了,从学生时代开始使用mfc做界面编程,到后来使用Duilib,QT,陆陆续续做了很长时间。做开发的大家都知道界面编程是十分头疼的,要面对随时变化多样的需求,尤其是后期维护,有可能面临用户或领导一个新需求就导致界面碎掉要重新开始的尴尬境地。而且目前C++的界面开发并不能紧跟潮流,往往其他编程语言或脚本一行代码解决的问题C++需要几十行甚至上百行,开发效率低周期长是致命的,并且使用mfc或者界面库并没有很高的技术含量,并不涉及到内部核心API的代码,相对简单的代码堆叠。现在是互联网时代,大数据,机器学习,数据挖掘大行其道,为了最求新技术,跟上最新技术的脚步,一年前转到了网络编程,目前在学习机器学习算法和linux高性能网络编程。从本人一年来的工作来看,网上资料并没有非常完整的网络编程教程,工作中都是东拼西凑,因此今天(2017年8月23日)开始决定写微博。目的在于记录自己的学习心得和工作心得形成体系,并且检验自己的成果,如果能对他人起到一些辅助启发作用,那更是求之不得,本人才疏学浅,在写作过程中,如有纰漏或错误望请各路大神指正,亦可互相交流,本人QQ1169129207,接受各种批评教育。


一、windows网络编程与linux网络编程对比

说到网络编程就不能不说两大系统的对抗,网上两个主流系统的战争由来已久。我觉得实际上不必要非要争出谁输谁赢,作为使用者的我们只要能够根据自己的需求与环境选择相应的系统进行开发即可。windows的好处是图形界面相当完善,自带iocp(完成端口)轻松应对十万级乃至百万级链接,后期维护成本低,而缺点当然是需要花钱,不可定制。而linux的好处在于可以定制,免费,开源,甚至内核都可以修改,其epoll通信模型能与iocp分庭抗礼,但是由于图形界面并不完善,其服务端的编写和部署都要求程序员和维护人员有较高素质,增加人力成本。这里并没有对比效率,因为相对来说,iocp和epoll效率都不低,都是两种系统特有的通信模型,没必要比较。由于本人目前工作中基本上都在用windows网络编程,因此这里会先写windows网络编程,后续会继续完成linux高性能网络编程。


二、windows下的通信模型对比

本文希望阅读者有一定的C++网络编程基础,因此一些基础的诸如什么是TCP/IP,网络分层模型等不会描述,主要是从应用实际出发,对比各种通信模型的优劣,如遇到不懂的名词请自行百度,由于完成例程和事件在在实际中很少用因此不做说明有需要了解的请百度。


1、同步I/O与异步I/O

同步I/O与异步I/O是相对的,而且都有阻塞和非阻塞的类型,千万不能把几种I/O弄混。当一个同步过程调用发出后,调用者不能立刻得到结果,调用者会等待结果产生。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。这里是百度的解释。我们可以用快递做一个比较形象的解释。


同步阻塞I/O

快递员来送快递,你很忙或者没在家,你告诉快递员,你别走,我忙完了找你,快递员说我不走,一直等你回来签收,中间不会询问你。

同步非阻塞I/O

快递员来送快递,你很忙或者没在家,你告诉快递员,你先走,我有空告诉你,快递员说我不走,一直等你回来签收,他会不停的询问你是不是忙完了。

异步阻塞I/O

快递员来送快递,你很忙或者没在家,你告诉快递员,你别走,我忙完了找你,快递员说我不走,在这等着,但是可能同一家公司或住宅有别人的快递,快递员可以边等边送别人的,并时不时问问你忙完了吗。

异步非阻塞I/O

快递员来送快递,你很忙或者没在家,你告诉快递员,你先走,我有空挂电话告诉你,你再来,快递员说那我先走了,你忙完了告诉我我再找你签收。

一般情况下网络编程不会使用异步阻塞I/O,因此本文会对比同步阻塞I/O的一般模型,同步非阻塞I/O的select模型,以及异步非阻塞I/O的iocp模型。


2、各种通信模型的对比及应用场景

(1)一般模型

网络通信的阻塞主要在接收和发送上,一般模型通过绑定、监听、接受连接后,就会等待客户端发送数据,客户端如果不发送数据就会阻断线程,一直等待,如果想要同时处理多个客户端,就要开启相应数量的线程,无法应对大规模链接,对一般主机而言几十个链接就显得很吃力了,何况更多链接。但是其非常简单不需要什么难理解东西,一般应用在简单的软件之间一对一或者一对少量客户端的场景。


(2)select模型

select模型是典型的同步非阻塞I/O,之所以称为select模型是因为其select函数,会通过select函数不停轮训服务端的socket,是否可以接收或者发送,但是由于FD_SETSIZE的限制,单线程只能轮训64个客户端,手动修改不太合适,并且不灵活,后续文章专门介绍select模型时会介绍如何打破此限制。select模型采用轮训方式因此相对来说其效率不是非常高,但是在windows和linux下都有该模型,并且在架构设计合理的情况下应对万级链接不成问题何况还有分布式,方便移植,接收数据处理简单,可以快速编写,逻辑简单,因此在对并发要求不是十分高的情况下,可以用select模型。libevent库就是使用的select模型。


(3)IOCP模型

IOCP模型微软提供的超级通信模型,windows下特有的高效高并发异步非阻塞I/O通信模型,采用真正的proactor模式,十几个线程即可轻松应对十万级链接,支持百万级链接,与linux下的epoll并称两大高效模型,但是IOCP因为其线程池会寻找空闲线程传递接收数据,因此并不能保证同一个客户端的数据被同一线程接收处理,因此其应用层协议要带有标识,并且其接收逻辑相对复杂,尤其是在文件接收或者单次不完整接收中,很容易出错,需要注意,但是编程难度并不影响其强大的性能,在高并发,高压力的服务器下非常推荐使用IOCP。其常用库有HP_Socket。


三、总结

在实际应用中很少使用一般的socket通信模型,会根据应用场景及需求采用select模型或IOCP模型,一般涉及到局域网通信软件,仪器检测等使用select模型,而类似于网游服务端,大型网站服务端采用iocp模型。当然不是绝对的,在好的架构下select模型也不是不能抗高并发,一对一通信也不是不能用iocp,采用何种通信模型是仁者见仁的事情,还需要使用者根据实际应用场景来选择。

这次先介绍到这里,如有问题请大神们指正,再说一下QQ1169129207,下两篇会详细介绍select及iocp,包括如何使用以及使用中的注意事项,并且有我自己编写的相对成熟的服务端代码供大家参考。












原创粉丝点击