客户端,人型服务端端,实体,接口这是C/S结构程序,请问是不是...

网站导航:
您现在的位置: >
> 浏览信息
iOS中基于 Socket 的 C/S 结构网络通信(中)
时间: 15:33
来源: 作者:学盟网
结合上一篇的知识,接下来将介绍基于 TCP 协议的 Socket
编程;由于 Socket 需要有客户端和服务端,那么现在实现的是关于服务端的简单程序。服务端采用的是CFStream 类来实现的。 copyright
这个服务端是把Xcode中的 Command Line Tool 来作为服务端的;当然,你也可以把 iPhone 作为服务端,但是要利用其他的框架,比如 AsyncSocket (/roustem/AsyncSocket)
,里面有分为 UDP 和 TCP 实现的 Socket,源程序里也有许多关于数据流的操作,可以作为深入理解来用,当然也是比较复杂的。 copyright
下面来看一下简单实现的 TCP 服务端程序:(TCPServer.m) 内容来自学生黑客联盟
#define PORT 9000
void AcceptCallBack(CFSocketRef, CFSocketCallBackType, CFDataRef, const void *, void *);
void WriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType, void *);
void ReadStreamClientCallBack (CFReadStreamRef stream, CFStreamEventType eventType,void *);
int main(int argc, const char * argv[])
/* 定义一个Server Socket引用 */
/* 创建socket context */
CFSocketContext CTX = { 0, NULL, NULL, NULL, NULL };
/* 创建server socket
TCP IPv4 设置回调函数 */
sserver = CFSocketCreate(NULL, PF_INET, SOCK_STREAM, IPPROTO_TCP,
kCFSocketAcceptCallBack, (CFSocketCallBack)AcceptCallBack, &CTX);
if (sserver == NULL)
return -1;
/* 设置是否重新绑定标志 */
int yes = 1;
/* 设置socket属性 SOL_SOCKET是设置tcp SO_REUSEADDR是重新绑定,yes 是否重新绑定*/
setsockopt(CFSocketGetNative(sserver), SOL_SOCKET, SO_REUSEADDR,
(void *)&yes, sizeof(yes));
/* 设置端口和地址 */
struct sockaddr_
memset(&addr, 0, sizeof(addr));
//memset函数对指定的地址进行内存拷贝
addr.sin_len = sizeof(addr);
addr.sin_family = AF_INET;
//AF_INET是设置 IPv4
addr.sin_port = htons(PORT);
//htons函数 无符号短整型数转换成“网络字节序”
addr.sin_addr.s_addr = htonl(INADDR_ANY);
//INADDR_ANY有内核分配,htonl函数 无符号长整型数转换成“网络字节序”
/* 从指定字节缓冲区复制,一个不可变的CFData对象*/
CFDataRef address = CFDataCreate(kCFAllocatorDefault, (UInt8*)&addr, sizeof(addr));
/* 设置Socket*/
if (CFSocketSetAddress(sserver, (CFDataRef)address) != kCFSocketSuccess) {
fprintf(stderr, "Socket绑定失败\n");
CFRelease(sserver);
return -1;
/* 创建一个Run Loop Socket源 */
CFRunLoopSourceRef sourceRef = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sserver, 0);
/* Socket源添加到Run Loop中 */
CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes);
CFRelease(sourceRef);
printf("Socket listening on port %d\n", PORT);
/* 运行Loop */
CFRunLoopRun();
/* 接收客户端请求后,回调函数
void AcceptCallBack(
CFSocketRef socket,
CFSocketCallBackType type,
CFDataRef address,
const void *data,
void *info)
CFReadStreamRef readStream = NULL;
CFWriteStreamRef writeStream = NULL;
/* data 参数涵义是,如果是kCFSocketAcceptCallBack类型,data是CFSocketNativeHandle类型的指针 */
CFSocketNativeHandle sock = *(CFSocketNativeHandle *)
/* 创建读写Socket流 */
CFStreamCreatePairWithSocket(kCFAllocatorDefault, sock,
&readStream, &writeStream);
if (!readStream || !writeStream) {
close(sock);
fprintf(stderr, "CFStreamCreatePairWithSocket() 失败\n");
CFStreamClientContext streamCtxt = {0, NULL, NULL, NULL, NULL};
// 注册两种回调函数
CFReadStreamSetClient(readStream, kCFStreamEventHasBytesAvailable, ReadStreamClientCallBack, &streamCtxt);
CFWriteStreamSetClient(writeStream, kCFStreamEventCanAcceptBytes, WriteStreamClientCallBack, &streamCtxt);
//加入到循环当中
CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
CFReadStreamOpen(readStream);
CFWriteStreamOpen(writeStream);
/* 读取流操作 客户端有数据过来时候调用 */
void ReadStreamClientCallBack(CFReadStreamRef stream, CFStreamEventType eventType, void* clientCallBackInfo){
UInt8 buff[255];
CFReadStreamRef inputStream =
if(NULL != inputStream)
CFReadStreamRead(stream, buff, 255);
printf("接受到数据:%s\n",buff);
CFReadStreamClose(inputStream);
CFReadStreamUnscheduleFromRunLoop(inputStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
inputStream = NULL;
/* 写入流操作 客户端在读取数据时候调用 */
void WriteStreamClientCallBack(CFWriteStreamRef stream, CFStreamEventType eventType, void* clientCallBackInfo)
CFWriteStreamRef
outputStream =
UInt8 buff[] = "Hello Client!";
if(NULL != outputStream)
CFWriteStreamWrite(outputStream, buff, strlen((const char*)buff)+1);
//关闭输出流
CFWriteStreamClose(outputStream);
CFWriteStreamUnscheduleFromRunLoop(outputStream, CFRunLoopGetCurrent(),kCFRunLoopCommonModes);
outputStream = NULL;
此段程序只涉及比较简单的数据流操作,详细的数据流操作请参考 AsyncSocket 的源码;至此,那么一个服务端就已经实现了。
内容来自学生黑客联盟
未完待续......
本文来自学盟网()
本文标题:
本文地址:
免责声明:本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。最近在做一个项目,用到了这些技术,所以稍微整理了一下,希望能对和我一样菜鸟级的任务有所帮助
微软公司推荐的.NET分层式结构一般分为三层架构,如图所示:
表示层(WC)
业务逻辑层(BBL)
数据访问层(DAL)
(1)数据访问层:有时候也称持久层,其功能主要是负责数据库的访问。简单地说就
是实现对数据表的 insert(增)、delete(删)、update(改)、select(查)的操作。
(2)业务逻辑层:是整个系统的核心,它与这个系统的业务(领域)有关。以陇原网上商城城为例,业务逻辑层的相关设计均和商城信息管理系统特有的逻辑相关,如果涉及数据库
访问,则调用数据访问层。
(3)表示层:是系统的 UI 部分,负责使用者与整个系统的交互。在这一层中,理想
的状态是不应该包括系统的业务逻辑。表示层中的逻辑代码仅与界面元素有关。
分层结构的优势:
(1):开发人员可以只关注整个结构中的其中某一层。
(2):可以很容易地用新的实现来替换原有层次的实现。
(3):可以降低层与层之间的依赖。
(4):有利于标准化。
(5):有利于各逻辑的复用。
概括来说,分层设计可以达到如下目的:分散关注、松散耦合、逻辑复用、标准定义。
一个好的分层结构可以使得开发人员的分工更加明确。一旦定义好各层次之间的接口,负
责不同逻辑设计的开发人员就可以分散关注、齐头并进。例如 UI 人员只需考虑用户界面的
体验与操作,业务领域的开发人员可以关注业务逻辑的设计,从而数据库设计人员也不必
为繁琐的用户交互而头痛了。每个开发人员的任务得到了确认,开发速度就可以迅速地提
松散耦合的好处是显而易见的。如果一个系统没有分层,那么各自的逻辑都紧紧纠缠
在一起,彼此间相互依赖,谁都是不可替换的。一旦发生改变,则牵一发而动全身,对项
目的影响极为严重。降低层与层之间的依赖性,既可以良好地保证未来的发展,在复用性
上也有明显优势。每个功能模块一旦定义好统一的接口,就可以被各个模块所调用,而不
用为相同的功能进行重复地开发。
分层结构也具有一些缺陷:
(1)降低了系统的性能。如果不采用分层式结构,很多业务可以直接访问数据库,以
此获取相应的数据,如今却必须通过中间层来完成。
(2)有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中
需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据
访问中都增加相应的代码。
在实体类中只定义了类的字段和属性,为什么不在里面定义方法?假如定义方法,是
定义业务逻辑层方法还是数据访问层方法?还是两者都需要定义?如果它们的方法都在实
体类中定义,那该如何实现分层?而且也不想在业务逻辑层调用数据访问层的对象。其实
只需要定义接口就可以了。方法定义在接口中,这样就不用担心破坏分层架构。也可以在
访问下一层的时候不用定义该类的对象,只需要一个接口就可以。
这就是实体类,抽象地说它只负责实体的表示和数据的传递,没有其他的功能需要。
工具类只是对本系统所用到的工具的一个封装,其实它和分层架构没有多大的关系,
在陇原商城要用到的工具类有三个,一个是缓存,一个是加密,另外一个是常用操作。
缓存可以提高系统的性能。ASP.NET 一共提供了三种可由 Web 应用程序使用的缓存:
输出缓存:它缓存请求所生成的动态响应。
片段缓存:它缓存请求所生成的各部分。
数据缓存:它以编程的方式缓存任意对象。
下面是我的商城所用的缓存类,可能有问题,希望大家指出:
using System.Collections.G
using System.T
using System.W
using System.Web.Caching;& //
namespace FlowerShop.Utility
public sealed class CacheAccess
/// &summary&
/// 存到缓存中
/// &/summary&
/// &param name="cacheKey"&用于引用该项的缓存键&/param&
/// &param name="cacheObject"&要插入缓存中的对象&/param&
/// &param name="dependency"&插入的对象的文件依赖项或缓存键依赖项。当任何依赖项更改时,该对象即无效,并从缓存中移除。如果没有依赖项,则此参数包含null。&/param&
public static void SaveToCache(string cacheKey, object cacheObject, CacheDependency dependency)
Cache cache = HttpRuntime.C
cache.Insert(cacheKey, cacheObject, dependency);
/// &summary&
/// 从缓存中取出
/// &/summary&
/// &param name="cacheKey"&键&/param&
/// &returns&值&/returns&
public static object GetFromCache(string cacheKey)
Cache cache = HttpRuntime.C
return cache[cacheKey];
将该方法声明为 static 的好处是可以不用声明一个对象,可以直接通过类名调用该方
法。在该方法中,参数 cacheKey 代表用于引用该项的缓存键,cacheObject 表示要插入缓
存中的对象,dependency 表示所插入的对象的文件依赖项或缓存键依赖项。当任何依赖项
更改时,该对象即无效,并从缓存中移除。如果没有依赖项,则此参数为 null。
Cache cache = HttpRuntime.C表示获取当前应用程序的
System.Web.Caching.Cache;
cache.Insert(cacheKey, cacheObject, dependency);表示将对象 cacheObject 插入
到键为 cacheKey 中。
这个类是从缓存中取出对象。首先还是获得一个缓存类的对象,然后通过传入的键值,
返回相应的对象。
工厂是分层架构的核心之处,工厂的理解对于理解三层架构有很大的帮助,如果想更
多的掌握工厂的知识,可以参考有关设计模式的书籍。
设计分层架构是为了实现层与层之间的可替换。如果现在需要换一种方式实现数据访
问层,但是又不想在表示层和业务逻辑层修改任何代码,而是最多只改一下配置文件就可
以。这该如何实现?此外,系统可以进行并行开发,即想让表示层的人与业务逻辑层的人
和数据访问层的人同时开发,这样开发的效率会大大提高。前面实现的接口就是让上层类
不能直接依赖于下层,即上层类不能直接实例化下层中的类。如果实现了下层的类又会怎
样?举个例子:在业务逻辑层定义了一个类 A,在数据访问层中定义了一个类 B,在 A 中定
义了一个 B 的对象,完成一种操作,但是突然想换一种方式实现数据访问层,那么需不需
要修改业务逻辑层的代码呢?答案是当然需要,因为在 A 中定义了 B 的一个对象,这也就
是定义接口的原因。定义了接口,上层类就不能具体依赖于下层类,而只依赖于下层提供
的一个接口,这就是所谓的松散耦合。
在工厂类中需要用到工厂类和依赖注入。工厂的概念属于设计模式的知识。工厂类顾
名思义,是指专门定义的一个类,目的是用这个类来负责创建其他类的实例。该类根据传
入的参数,动态决定应该创建哪个产品类。依赖注入又名 IOC(Inversion of Control),
中文为控制反转。许多应用都是由两个或更多个类通过彼此合作来实现业务逻辑,这使得
每个对象都需要与它合作的对象的引用,如果这个获取过程要靠自身实现,那么将导致代
码高度耦合且难以测试。所以应用依赖注入以后,如果对象 A 需要调用另一个对象 B,在对
象 B 被创建的时候,由依赖注入将对象 B 的引用传给 A 来调用,即将 B 的接口返回给 A,A
可以直接通过 B 的接口实现相应的操作。
在.NET 中怎样实现根据传入参数动态决定应该创建哪个产品类?这如果在以前实现
起来会很复杂,但是.NET 平台的反射机制提供了解决方案。应该怎样利用工厂类和依赖注
入机制来实现分层架构呢?首先考虑分层的要求,分层是在别的层次不改动的情况下来实
现可以更换不同层次的实现,那这是不是说传入工厂类的参数如果是某个层次的某个实现,
那么就可以通过反射来动态地调用该层次的实现,如果实现了动态加载不同的实现,但是
能保证动态加载后,程序仍能稳定运行吗?或者说应该怎样让程序可以稳定地运行下去。
这还是需要接口,前面定义了业务逻辑层和数据访问层的接口,每一层的实现,无论该层
有多少种实现都只是重写方法而已,所以用接口能够实现无缝的结合。依赖注入只是一种
机制,目的是减少耦合度,通俗地来讲就是避免用 new 来实现类,而是通过接口来实现。
贫血模式和充血模式的简单区别
贫血模型:是指领域对象里只有get和set方法,或者包含少量的CRUD方法,所有的业务逻辑都不包含在内而是放在Business Logic层。
优点是系统的层次结构清楚,各层之间单向依赖,Client-&(Business Facade)-&Business Logic-&Data Access(ADO.NET)。当然Business Logic是依赖Domain Object的。似乎现在流行的架构就是这样,当然层次还可以细分。
该模型的缺点是不够面向对象,领域对象只是作为保存状态或者传递状态使用,所以就说只有数据没有行为的对象不是真正的对象。在Business Logic里面处理所有的业务逻辑,在POEAA(企业应用架构模式)一书中被称为Transaction Script模式。
充血模型:层次结构和上面的差不多,不过大多业务逻辑和持久化放在Domain Object里面,Business Logic只是简单封装部分业务逻辑以及控制事务、权限等,这样层次结构就变成Client-&(Business Facade)-&Business Logic-&Domain Object-&Data Access。
它的优点是面向对象,Business Logic符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重。
缺点是如何划分业务逻辑,什么样的逻辑应该放在Domain Object中,什么样的业务逻辑应该放在Business Logic中,这是很含糊的。即使划分好了业务逻辑,由于分散在Business Logic和Domain Object层中,不能更好的分模块开发。熟悉业务逻辑的开发人员需要渗透到Domain Logic中去,而在Domian Logic又包含了持久化,对于开发者来说这十分混乱。& 其次,因为Business Logic要控制事务并且为上层提供一个统一的服务调用入口点,它就必须把在Domain Logic里实现的业务逻辑全部重新包装一遍,完全属于重复劳动。
如果技术能够支持充血模型,那当然是最完美的解决方案。不过现在的.NET框架并没有ORM工具(不算上开源的NHibernate,Castle之类),没有ORM就没有透明的持久化支持,在Domain Object层会对Data Access层构成依赖,如果脱离了Data Access层,Domain Object的业务逻辑就无法进行单元测试,这也是很致命的。如果有像Spring的动态注入和Hibernate的透明持久化支持,那么充血模型还是能够实现的。
选择了.NET平台开发,就是选择了开发高效、功能强大应用简单,最适合的模型就是贫血模型,或表数据入口,既有编译器和语言平台很好的支持,也符合微软提倡的开发模式。如果跟潮流在项目中使用充血模型,现有的ORM工具都很复杂难用,光是维护大量的映射文件都成问题。说贫血不够OO,它的Domain Object不够丰富,能把项目做好了,有一定的扩展能力和伸缩行就行了,也不一定要讲究优雅的面向对象。正如SOA,讲究松耦合、高内聚,服务端给客户端提供的服务,也就是一系列的方法调用加上DTO而已,不管服务的内部是不是面向对象的实现,至少它暴露出来的是过程式的服务。本文链接
[ASP教程]贫血模式和工厂模式,实体类,工具类以及三层架构[ASP教程]贫血模式和工厂模式,实体类,工具类以及三层架构 08:00:06 最近在做一个项目,用到了这些技术,所以稍微整理了一下,希望能对和我一样...浅谈三层架构 通过这个,+Java开发模式经验。终于相通了,动软到底... 因此。这里它还增加了一个工厂模式。 我这里分析...与三层架构毫无关系,就是常用的开发模式中存放类(.../DbHelperSQL等,为DAL提供访问数据库的辅助工具类。...C#中的三层_百度知道2个回答 - 提问时间: 日业务实体Model:用于封装实体类数据结构,一般用于映射数据库的数据表或视图,用以...通用类mon:通用的辅助工具类 工程模式:简单工厂模式又称为静态工厂方法(...三层架构 - 随笔分类 - Kencery - 博客园贫血模式和工厂模式,实体类,工具类以及三层架构 摘要: 最近在做一个项目,用到了这些技术,所以稍微整理了一下,希望能对和我一样菜鸟级的任务有所帮助三层架构...分析工厂模式三层架构的认识和分析 - 豆丁 - 1 - 分析工厂模式三层架构的认识和分析 我们所...业务实体Model:用于封装实体类数据结构,一般用于映射...通用类mon:通用的辅助工具类。 三层架构 三层...浅尝三层架构 - 教程_编程_开发技术文章 - 红黑联盟一个体现Java接口及工厂模式优点的例子 - 子在川上曰 - BlogJava三层架构浅析 - mile - 博客园三层架构浅析-中国学-中国IT综合门户站 “三层架构”中的三层是指:表现层(UI)、业务逻辑... 数据访问工具类 数据访问类使用DbProviderFactory实现...,MVC可归于表示模式,工厂模式可归于分布式系统模式。...传智播客java培训 MVC三层架构模式_记得要忘记_新浪博客 传智播客java培训 MVC三层架构模式 ( ... |__开发工具类 |__创建junit测试..itcast.... 设计一个实体类 代表用户提交的表单 并为完成的...winform学习日志(十九)---真正三层架构之登录__程序员俱乐部基于平台的分层架构实战_甜梦文库|文库百度|百度文库下载|...架构的(题目叫“基于 平台的分层架构与设计模式...一般来说, 实体类可以分为“贫血实体类”和“充血...访问层接口族 Utility——存放各种工具类及辅助类...《【经典自学Java视频教程】/JavaSE视频/Java项目视频/Struts视频...状态: 精华资源 摘要: 主讲人: 王勇杜聚宾 发行日期: 日 对白语言: 普通话 文字语言: 简体中文 时间:
13:35:20 发布| 2014/...设计模式--基于C#的工程化实现及扩展(china-pub 首发) - china-... 1.4.1 认识 framework提供的主要配置实体类 ...相信这本案头的工具书可以提供你一个不错的思维模式...但不管是创建型模式、结构型模式还是行为型模式,归根...基于ASP开发的三层架构JQuery版本CRM企业级客户管理系统项目...《模式:工程化实现及扩展(设计模式C#版)》(王翔)【摘要 书评 试读...设计模式——基于C#的工程化实现及扩展-王翔-语言与开发工具-文轩模式,帮你造就有弹性、能扩充、易维护的软件实体。... 3.1.1 最简单的工厂类 3.1.2 根据规格加工...第3篇 结构型模式——针对变化组织灵活的对象体系 ...设计模式:基于C#的工程化实现及扩展txt免费下载|在线阅读|全集|...第3篇结构型模式的重点在于如何通过灵活的体系组织不... 1.4.1 认识 Framework提供的主要配置实体类 ... 第5章 抽象工厂模式 5.1 经典回顾 5.2 按计划...分包为6个模块。增加HTTP接口。增加部分工具类。对uibind增加对...增加HTTP接口。增加部分工具类。对uibind增加对view中的控件的绑定。 ... 45 46 * 打开的模式。值为Context.MODE_APPEND, Context.MODE_PRIVATE, 46... 开发模式和架构比较 - 晋商风范技术博客 - 博客频道 - CSDN...业务实体Model:用于封装实体类数据结构,一般用于映射数据库的数据表或视图,用以...通用类mon:通用的辅助工具类 工程模式:简单工厂模式又称为静态工厂方法(...[计算机]三层架构关系 - 豆丁业务实体 Model:用于封装实体类数据结构,一般用于映射数据库的数据表或视图,用以...通用类mon:通用的辅助工具类 工程模式:简单工厂模式又称为静态工厂方法(...C#三层架构教程(含示例代码)_百度文库&评分:4/5&121页一般来说,实体类可以分为“贫血实体类”和“充血...存放各种工具类及辅助类 2 这只是一个初期架构,...数据访问层工厂,用于获取相应的数据访问层对象 ///...转 三层架构与养猪 - 豆丁工厂模式或MVC 不用说,就简单的说说三层架构。为了...用于封装实体类数据结构,一般用于映射数据库的数据表...l 通用类mon:通用的辅助工具类。 在第5.2 ...asp 三层架构解析 - 豆丁“简单的三层结构”,至于“抽象工厂模式”放后面来...这个实体类,如果你需要一个admin 的实体,那么你需要...l 通用类mon:通用的辅助工具类。 在第5.2 ...C#三层架构教程(含示例代码)_百度文库&评分:4/5&38页一般来说,实体类可以分为&贫血实体类&和&充血实体...存放各种工具类及辅助类 2 这只是一个初期架构, ... 实现工厂 下面使用两个辅助类,实现数据访问层工厂...C#三层架构教程(含示例代码)_免费下载_百度文库&评分:3.5/5&34页我们在这个 Demo 中用的实体类将是 &贫血 实体类&。 大多情况下, 实体类和...存放各种工具类及辅助类 2 这只是一个初期架构, 主要是将整个系统搭一个框架,...探讨贫血结构的系统重构成DDD模式讨论第3页: - ddd,领域驱动设计,...7条回复&-&发帖时间:&日探讨贫血结构的系统重构成DDD模式讨论第3页: - ddd,领域驱动设计,...7条回复&-&发帖时间:&日探讨贫血结构的系统重构成DDD模式讨论第3页: - ddd,领域驱动设计,...7条回复&-&发帖时间:&日分享高效的实体类操作类,分析其优势,可自己写替代EF的ORM框架-...29条回复&-&发帖时间:&日一个体现Java接口及工厂模式优点的例子 - hahachinahaha的专栏 - ... People是一个实体类,代表一条记录。三个字段 oid...因为OracelDataOperate等都是无状态的工具类, * ... 一个体现Java接口及工厂模式优点的例子 shizhu2: ...C#MVC架构、工厂模式的区别_中华文本库业务实 体 Model:用于封装实体类数据结构,一般用于映射数据库的数据表或视图,...通用类库mon:通用的辅助工具类 工程模式:简单工厂模式又称为静态工厂方法(...一个体现Java接口及工厂模式优点的例子_Java编程_软件开发_文档_...架构总体采用工厂模式,而且是最复杂的抽象工厂模式。... People是一个实体类,代表一条记录。三个字段 oid...模式,因为OracelDataOperate等都是无状态的工具类,...thrift应用举例(c/c++作为服务端、java作为客户端) -
- ITeye技术网站
博客分类:
最近做的一个项目,后端服务是c++写的,因所有参与这个项目的同事除了me之外,他们都不会c/c++语言。没有办法,我就承担了这个有意思的任务。下面通过实战例子,来剖析thrift的应用。
1.thrift是干什么用的?
2.thrift语法?
3.实战例子
3.3 实战例子
1.Thrift是干什么用的?
Thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发。它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, and OCaml 这些编程语言间无缝结合的、高效的服务。Thrift最初由facebook开发,07年四月开放源码,08年5月进入apache孵化器。Thrift允许你定义一个简单的定义文件中的数据类型和服务接口,以作为输入文件,编译器生成代码用来方便地生成RPC客户端和服务器通信的无缝跨编程语言。
2.Thrift语法
请参考网上其他文章。网上很多,不在赘述。重点了解:基本类型、容器、结构体、枚举、服务即可。
2.1基本类型:
bool: 布尔值 (true or false), one byte
byte: 有符号字节
i16: 16位有符号整型
i32: 32位有符号整型
i64: 64位有符号整型
double: 64位浮点型
string: Encoding agnostic text or binary string
Note that: Thrift不支持无符号整型,因为Thrift目标语言没有无符号整型,无法转换
Thrift容器与流行编程语言的容器类型相对应,采用Java泛型风格。它有3种可用容器类型:
list&t1&: 元素类型为t1的有序表,容许元素重复。
set&t1&:元素类型为t1的无序表,不容许元素重复。
map&t1,t2&: 键类型为t1,值类型为t2的kv对,键不容许重复。
容器中元素类型可以是除了service外的任何合法Thrift类型(包括结构体和异常)。
2.3 枚举和结构体
枚举,和我们平常理解的枚举一样。
这里只强调结构体就是类似于c/c++中的结构体(几乎一模一样)。类似于java中的实体bean。例子如下:
enum TweetType {
RETWEET = 2, // (2)
struct TxtClass{
1: string text,
2: string classId,
3: double score,
在流行的序列化/反序列化框架(如protocal buffer)中,Thrift是少有的提供多语言间RPC服务的框架。这是Thrift的一大特色。Thrift编译器会根据选择的目标语言为server产生服务接口代码,为client产生stubs。
这里就是thrift自动会生成的方法,我们的服务端也需要器生成的方法中进行编码。例子如下:
service Twitter {
// A method definition looks like C code. It has a return type, arguments,
// and optionally a list of exceptions that it may throw. Note that argument
// lists and exception list are specified using the exact same syntax as
// field lists in structs.
void ping(),
bool postTweet(1:Tweet tweet);
TweetSearchResult searchTweets(1:string query); // (3)
// The 'oneway' modifier indicates that the client only makes a request and
// does not wait for any response at all. Oneway methods MUST be void.
oneway void zip()
&!--[if !supportLists]--&1.
3.&!--[endif]--&实战例子
centOS6.4 64位操作系统
首先,从官网上下载thrift-0.8.0版本,你可以下载最新的版本。
其次,从网上下载ant 和ivy。放在/usr目录下。
Ant下载路径:
Ivy下载路径:
一切准备就绪,即可安装:
3.2.1安装ant和ivy(root用户)
第一步:安装 切复制ivy-2.2.0.jar到/usr/local/apache-ant-1.8.2/lib/目录中
# tar xzvf apache-ant-1.8.2-bin.tar.gz -C /usr/local
# tar xzvf apache-ivy-2.2.0-bin-with-deps.tar.gz -C /usr/local
/usr/local/apache-ivy-2.2.0/ivy-2.2.0.jar
/usr/local/apache-ant-1.8.2/lib/
第二步:编辑vim
/etc/ profile ,添加如下两行
export ANT_HOME=/usr/local/apache-ant-1.8.2
PATH=$ANT_HOME/bin:$PATH
第三步:解压thrift压缩文件。我用的是thrift-0.8.0.tar.gz
thrift-0.8.0.tar.gz
进入到thrift-0.8.0目录
第四步:包的检查、安装(如果缺少包,请安装缺少的包)
./configure --prefix=/usr/local/ --with-boost=/usr/local --without-php
make install
在终端输入:thrift –version
查看是否安装成功。
3.3 实战例子
特别注意:如下例子:演示的是thrift-0.7.0版本(因我服务器上安装的此版本)
1.定义thrift文件:user.thrift
struct User{
1: string uid,
2: string uname,
3: bool usex,
4: i16 uage,
service UserService{
void add(1: User u),
User get(1: string uid),
2.通过thrift的shell工具命令生成c++,java代码框架
thrift -r --gen cpp user.thrift
thrift -r --gen java user.thrift
通过执行以上命令:会生成子目录gen-cpp,gen-java。
3.通过执行如下命令,生成C/C++服务端代码
cp gen-cpp/UserService_server.skeleton.cpp UserServer.cpp
4.修改服务端的代码,如下所示
// This autogenerated skeleton file illustrates how to build a server.
// You should copy it to another filename to avoid overwriting it.
#include &string&
#include &iostream&
#include "UserService.h"
#include &config.h&
#include &protocol/TCompactProtocol.h&
#include &server/TSimpleServer.h&
#include &transport/TServerSocket.h&
#include &transport/TBufferTransports.h&
#include &concurrency/ThreadManager.h&
#include &concurrency/PosixThreadFactory.h&
#include &server/TThreadPoolServer.h&
#include &server/TThreadedServer.h&
using namespace ::apache::
using namespace ::apache::thrift::
using namespace ::apache::thrift::
using namespace ::apache::thrift::
using namespace ::apache::thrift::
using boost::shared_
class UserServiceHandler : virtual public UserServiceIf {
UserServiceHandler() {
// Your initialization goes here
void add(const User& u) {
// Your implementation goes here
cout && "调用add方法" &&
void get(User& _return, const std::string& uid) {
// Your implementation goes here
_return.uid = "001";
_return.uname = "dengqs";
_return.usex = 1;
_return.uage = 3;
cout && "uid = " && _return.uid &&
cout && "调用get方法" &&
int main(int argc, char **argv) {
int port = 9090;
shared_ptr&UserServiceHandler& handler(new
UserServiceHandler());
shared_ptr&TProcessor& processor(new UserServiceProcessor(handler));
shared_ptr&TProtocolFactory& protocolFactory(new TCompactProtocolFactory());
shared_ptr&TTransportFactory& transportFactory(new TBufferedTransportFactory());
shared_ptr&TServerTransport& serverTransport(new TServerSocket(9090));
shared_ptr&ThreadManager& threadManager = ThreadManager::newSimpleThreadManager(10);
shared_ptr&PosixThreadFactory& threadFactory = shared_ptr&PosixThreadFactory&(new PosixThreadFactory());
threadManager-&threadFactory(threadFactory);
threadManager-&start();
printf("start user server...\n");
TThreadPoolServer server(processor, serverTransport,
transportFactory, protocolFactory, threadManager);
server.serve();
注意:我这里使用的是TCompactProtocol,则需要#include &config.h& ,还有就是Blocking的多线程服务器。
5.书写Makefile文件,如下所示:
BOOST_DIR = /usr/include/boost/
THRIFT_DIR = /usr/local/include/thrift
LIB_DIR = /usr/local/lib
GEN_SRC = ./gen-cpp/user_types.cpp ./gen-cpp/user_constants.cpp ./gen-cpp/UserService.cpp
default: server
server: UserServer.cpp
g++ -g -o UserServer -I${THRIFT_DIR} -I${BOOST_DIR}
-I./gen-cpp -L${LIB_DIR} -lthrift UserServer.cpp ${GEN_SRC}
注意:在当前目录下,执行:make命令。看是否有可执行文件UserServer生成。如果有,则编译成功。
6.书写简单的运行脚本:run.sh文件,如下所示:
nohup ./UserServer
7.以上步骤,c++服务端操作完毕,执行如下命令开启服务:
./UserServie
8.写java client文件Demo.java
注意需要引入thrift相关的jar。并且需要把第2步生成的gen-java目录下的文件拷贝到你的测试程序中。
import org.apache.thrift.TE
import org.apache.thrift.protocol.TCompactP
import org.apache.thrift.protocol.TP
import org.apache.thrift.transport.TS
import org.apache.thrift.transport.TT
import org.apache.thrift.transport.TTransportE
import com.intyt.thrift.client.U
import com.intyt.thrift.client.UserS
public class Demo {
public void start(){
String ip = "10.x.x.x"; //服务端的ip
int port = 9090;//端口
TTransport socket = new TSocket(ip,port);
TProtocol protocol = new TCompactProtocol(socket);
UserService.Client client = new UserService.Client(protocol);
socket.open();
User u = new User();
u.uid="003";
u.uname="dengqs_test";
client.add(u);
System.out.println(client.get(u.uid));
socket.close();
}catch (TTransportException e) {
e.printStackTrace();
} catch (TException e) {
e.printStackTrace();
public static void main(String[] args) {
Demo demo = new Demo();
demo.start();
以上步骤,可查看服务端和客户端时候有相关打印输出。如果有预期的打印输出,则测试成功。
祝你好运。
dengqsintyt
浏览: 9253 次}

我要回帖

更多关于 人型服务端 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信