构建 复杂系统的TCP/IP网络架构

          为了整治工厂,张瑞敏上任后就制定了13条规章制度,其中第一条是“不准在车间随地大小便”。后人读到这里,大概都会笑到喷饭,但是在当时却是一件很严肃的事情,在很多国营工厂里,随地大小便是一件不被禁止并司空见惯的行为,张瑞敏的制度贴出半年多后,随地大便的人没有了,但是小便的却还没能马上杜绝。                      ----吴晓波  《激荡三十年》

    复杂系统需要同时对于n多个Client提供服务,但是,网络传输的不确定性,决定了系统的复杂性。所以,一套成熟的网络框架对于网络服务的重要性。目前,已经有的ACE(参考<C++网络编程第一卷>),著名的QT里面也有网络模块。最近,新公司需要做一套新系统,于是,自己也设计了一套框架。

    Richard Stevens的《TCP/IP 详解 第一卷》(虽然上面有些内容已经有了变化),《Unix网络编程 第一卷》是学习网络的基础书籍。到现在,查看网络API的时候,第二本书还是Frist choice。在没有做DVR之前,我一直认为C语言是做嵌入式设备系统的最佳选择,但是,在如今主频都超过400MHz的嵌入式设备(TI Netra解决方案主频都到了1G,而中高端智能手机都超过了1G)来说,驱动用C,而其他模块用C++是最佳的选择,开发效率提高很多倍。但是,对于C++的使用,这套Posix networkAPI使用起来还是不方便,如果涉及到Cross Platform的项目,直接使用更加的麻烦。所以,网络框架第一要务就是封装这些接口为class。

    综上,我们先把这一组 sockaddr进行封装,包括 sockaddr_in, sockaddr_in6, sockaddr_storage,sockaddr_un(不过因为windows不支持unix Socket,所以不使用)。这组地址是其他操作的前提,所以可以封装提供的Interface,包括setAddr(char *ip,int port), std::string getIP(int *port)等。

    接着就是把API:, socket,bind, connect, accept,recv,send,recvto, sendto, writeV等接口封装(里面没有使用write和read,因为可以由send和recv来实现,且MSDN告诉我们winsock是使用recv和send的。) 参考<C++网络编程第一卷>ACE的封装方式,包括 网络地址(IPv4和Ipv4,UnixSocketAddr,Sock Storage等),UDP和TCP的SockTcp和SockUdp。另外特别指出的是,ACE把accepte独立成一个模版类,但是我认为,放到socktcp中也一样的。

    接下来就是最复杂的线程池设计。

    n多年前,简单的网络应用,对于一个连接是使用一个线程去处理的。但是,复杂的service应用,如果每个链接一个线程的话,会导致n多个线程了,资源的消耗可想而知。举个例子,目前RTSP点播系统,可能一台服务端对应n多个用户,但是,如果同时有10个客户端都同时来点播,那就要多10个线程(假设只有视音频流的链接),如果20个就20个线程,100个就要100个线程。1024个就要1024个线程,linux下缺省一个进程最多就支持1024个线程。那一个service服务就支持1024个客户?答案是这种方式不合理,目前普遍使用的方法就是线程池,初始化网络服务线程为固定个数(或者递增式的)。推荐初始化 cpu内核数的整数倍个。

    线程池,如何设计?我们不是算法专家,只是engineer。我采用了其中的Leader/Follower模式,即 任意时刻线程池分为一个leader和n-1个follower线程,线程按需轮流做leader。不过,在平台软件可以用这种模式,但是如果是嵌入式设备的话,个人认为这种模式过于复杂,不适合嵌入式设备。其他详细的介绍大家可以google搜一下。

    简单讲我的线程池设计就是使用I/O复用函数 select。且大多时候,socket都设置为非阻塞的方式。然后,用mutex进行最小区域的锁。然后,其中一个leader线程select,如果有socket有可读可写的话,这个线程进行处理,让出leader,其他的一个线程作为leader。以此类推。另外,一定要在这种模式下加上timeout机制,我曾经遇到过一个消息处理的中间件,由于没有timeout机制,导致应用处理的复杂度。核心部分就这么多。还有消息处理,那就使用一个unixsocket的方式去实现。windows就自己实现一套这样的API。

    这种机制不好的地方就是,所有的线程都共享一个任务队列,存在一个临界区。阻塞式的的调用(RequestResponse一起)。第一个不能解决,第二个外部用一种阻塞机制去完成(当然其中包含timeout)。封装了一个class来处理。

    整个框架就是这么多。经过一些测试,work还能满足需求。

    Good Luck!

   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值