使用Socket API(上)
2009年11月30日
原帖链接http://blog.sina.com.cn/s/blog_59fd7a6f0100fs8y.html~type=v5_one&label=rela_prevarticle
真正的源~http://wiki.forum.nokia.com/index.php/使用Socket_API
简介通过这篇文章我们想为大家带来一些Symbian操作系统的有关sockets API的基本介绍。 本文的读者应该是希望在他们的应用程序中增添socket通信功能的Symbian操作系统的开发者,本文不仅提供了理论介绍,同样给出了可供实践参考的代码范例。
本文包含的内容有:
概括介绍了有关socket通信的有关组件。概括介绍了socket服务架构以及使用两个主要API类RSocketServ和RSocket的使用。讨论了创建两个终端之间进行通信的过程。讨论了socket之间通信的不同模式:基于一串数据流的模式以及基于离散消息的模式。一个如何使用活动对象来进行socket连接的实践范例。有关Socket的服务构架本文的一个内容是介绍给大家如何将基于Socket服务的通信功能加入到应用程序中来。尽管如此,计算机通信系统乃是一个十分复杂的系统,本文介绍的基于socket服务的通信仍然是在一个相对比较高级的层次,没有深入底层探讨的话题和技术。要想让socket服务来发挥作用,许多底层支持软件将是必须的。
下图说明了socket服务组件在Symbian系统的通信子系统中的哪一层位置,扮演如何一个角色。
[b]Symbian OS通信系统组件[/b]
首先我们来考虑传输层协议。上图的Internet互联网协议和红外协议,从Symbian 6.0之后支持的蓝牙®无线通讯技术都在这一层中。
当我们谈到Internet协议时,我们其实包括了一个隐式的依赖动作,那就是向ISP(互联网服务提供商)进行拨号连接。因此,如图所示我们可以看到Symbian系统提供了拨号网络接入组件。而在本图中,最重要的的系统组件是电话通信服务组件。
最终,我们需要设计到一个硬件设备,有了硬件我们才可以在选定的网络环境中接收和发送数据。上图的核心部分就是使用Internet协议的拨号接入网络,并且显示了串行通信组件在整个通信系统扮演了如何的角色。串行通信服务组件通过特定的硬件设备驱动,完成了硬件设备与它周围环境的通信。
什么是socket?那么什么是socket呢? 用一句引自伯克利(Berkeley)UNIX关于socket实现的经典定义来回答就是“socket就是通信终端”。
那究竟是什么意思呢?
一个socket代表了一条通信‘通道’逻辑上的终端。而实际上讲,socket是物理网络地址和逻辑端口号的一个集合,而这个集合可以向另外一个位置的与他具有相同定义的socket进行数据传输。
因为socket是由机器地址和端口号来区分/识别的,那么在一个特定的计算机网络上,每一个socket都是以此方式被唯一识别的。这就使得应用程序可以唯一地去定位网络上的另外一个位置的socket。
注意:对于同一台机器上的两个socket,他们是完全具备彼此间进行通信的可能的;在这种情况下,两个socket具有相同的主机地址,但是他们拥有不同的端口号。
主机地址和端口号的组合,对于不同协议是不同的。在socket的经典应用中,网络通信使用的是IP(Internet Protocol)协议,但是实际上socket是支持很多其它协议的,对于这方面的信息稍后会提到。
正如我们将会看到的,不管我们选择怎样的通信协议(传输层),我们都可以使用同一种已成熟的socket API来实现通信。
协议模块如上文所述,socket的经典应用是在TCP/IP协议的计算机网络上,使两个逻辑端点之间展开通信活动。最著名的应用TCP/IP的计算机网络,当然就是Internet了。
绝大多数socket系统的实现都限定在了TCP/IP网络的通信上。
但是,Symbian系统的socket服务组件,就实现了更多的内容;不仅如此,它还为其他组件提供了支持模块插件协议的基础构架。这就使得Symbian公司和它的开发伙伴们大大延长了socket服务组件以及支持socket的应用程序的应用时间。
由于新协议和传输层的引入,支持了新的传输‘语言’或协议的协议组件,从而使得socket服务组件可以随之适应新的应用环境。
随着Symbian系统第五版的socket服务组件支持了TCP/IP和红外协议的稽核。在Symbian 6.0版的时候,就增加了蓝牙®无线技术和短信息服务插件。
协议模块其实就是标准的Symbian系统动态链接库(DLL)。他们都有共同的UID2--KUidProtocolModule(0x1000004A)来表示他们的类型,并且拥有特殊的扩展名*.PRT。
一个关于经典系统的方面,就是socket服务对PLP(Psion Link Protocol)协议也是支持的。PLP被用来进行Symbian系统的手机和运行Microsoft Windows的台式或笔记本计算机之间进行通信。PLP的一个应用就是Symbian Connnect - 目前的被用于名为‘PsiWin’的Psion计算机。
socket服务组件可以以两种方式加载协议模块:
最通常的做法就是,协议模块会在第一个使用该协议的socket被打开的时候进行加载。另外一种做法是,应用程序可以显式地加载协议模块。这种做法的一个好处就在于,当协议加载需要一个比较长的时间的时候,应用程序或用户可以得到相应的提示。使用这种方法调用的API在本文的后面将会进行讨论。要说明的几点:一个协议模块可以包含多种协议实现。比如,在TCPIP.PRT模块中,就包含了UDP、TCP、ICMP、IP以及DNS协议的实现。单个协议的实现可以通过位于\system\data\.的.esk文件进行映射。而每个协议模块都有一个.esk文件来指定该模块所包含的协议,以及每个协议在插件模块中所处的索引位置。
传输的独立性上文已经提到,socket服务组件的插件架构特性可以使得新的协议模块在任何时间被安装到一部Symbian系统的手机当中。
这个架构可以使得socket服务组件来实现独立传输层的概念。借助于提供一个通用的核心socket API接口,这种架构就可以处理所有一般性数据传输系统的需求,并且通过添加特定协议的协议模块,socket服务组件就可以被广大应用程序开发者来给自己的产品增添通信功能,从而省下了大量的开发通信子系统的时间。
随着时间的发展,新的协议逐步登上历史舞台,协议模块都将会为了适应socket接口而被重写。而应用程序开发者,他们只需要增添协议新近引入的属性或者动作,来支持新的协议即可,Socket服务组件便会使用新的协议,借助操作系统底层的通信组件,来完成通信机制,而并不会影响到上层应用程序开发者的接口和开发。
总而言之,socket服务组件可以让应用程序开发者在仅仅维护一套核心API接口的情况下,可以借助操作系统的通信子系统来使用多个协议,从而减少了自己的开发工作量以及开发时间。
“客户端-服务器”接口Symbian系统的一个特点就是它具有一个体积很小的微内核(micro-kernel),因此我们只能把必须和硬件设备交互以及进行主机控制的核心服务放在内核端运行。而另外许许多多的系统服务只能以用户模式的服务器线程的形式运行,通常被称为‘系统服务器’。
socket服务组件就是这些‘系统服务器’中的一个,第三方应用程序就借助公开的客户端API,通过该组件完成通信功能。其中最重要的四个类为:
[b]RSocketServer[/b]: 这个类是用来建立和socket服务组件之间的连接以及获取必要的资源的。在客户端-服务器架构的定义中,该类表示了应用程序与socket服务组件之间建立连接的会话。所有的其他客户端接口类,在使用中都需要一个被打开的本类的实例来进行操作。[b]RSocket[/b]: 这个类表示了一个socket连接。一个标准的应用程序可能会在不同时间的时候,拥有若干个RSocket的实例在同时进行操作。[b]RHostResolver[/b]: 这个类用来提供主机名称解析服务的接口。[b]RNetDatabase[/b]: 这个类用来提供网络数据库访问的接口。RSocket, RHostResolver & RNetDatabase 均表示了一个给定的应用程序与socket服务组件之间进行的会话下的子会话,而应用程序与socket服务组件之间的会话就是一个RSocketServer的实例。
sockets服务器的主要类socket服务组件提供了两个主类,供他的客户端访问内部的API。
[b]RSocketServ[/b]: 在每个应用程序线程中,只要需要连接socket请求,他就必须使用一个本类的实例,来为其他连接(会话)提供socket服务。[b]RSocket[/b]: 每一个需要使用socket的应用程序线程,同样也需要一个或多个RSocket对象,这些对象就是子会话了。下面的两个部分将会介绍会话和子会话类(RSocketServ 和 RSocket)的详细内容。
使用RSocketServ类RSocketServ类扮演了一个十分重要的角色,因为它是客户端应用程序与socket服务组建之间的连接会话。
但是,客户端应用程序并不直接使用这个类来进行数据的发送和接收,或者创建一个远程通信端点;要完成这些任务的话,使用的是RSocket类,这个类将会在稍后进行介绍。
RSocketServ可以让客户端应用程序来向socket服务组件发起一些查询,查询的内容包括服务器支持的协议个数以及支持哪些协议,每个支持协议的具体信息等等。
希望使用socket的客户端应用程序,都将需要自己创建一个RSocketServ类的实例对象,用这个对象来表示该客户端应用程序和socket服务之间的会话。每一个独立的socket连接,都是一个独立的RSocket类的实例对象。可以说,在一个客户端应用程序中,该程序的RSocketServ类对象就是所有的RSocket类对象的容器。
RSocketServ类的两个常用函数就是Connect()和StandardProtocol()。
建立一个连接到sockets服务的会话使用Connect()方法,应用程序就可以建立与socket服务之间的一个会话。它仅仅使用一个参数--该会话所提供的消息通道的个数。
TInt Connect (TUint aMessageSlots);
消息数参数被用来限定应用程序向socket服务所同时并发的异步操作的请求通道数。每一个同步请求都将占用一个消息通道,并且请求准备中的异步操作也将占用一个消息通道。
一个普通socket进行的读写通信操作,都是异步进行的,也就是说这样的操作要占用两个消息通道。如果socket也可以进行同步操作的话,那么我们其实并不需要指定过多的消息通道,因为同步操作的消息通道是由socket客户端-服务器框架来完成的。对于你的应用程序在同一个时间内会使用到多少个消息通道,这完全是由你来断定的,而在大多数情况下,我们要尽可能的减少同时请求的消息通道数。
如果我们不指定任何特定的值,那么系统会使用一个默认值作为消息通道个数的参数:KESockDefaultMessageSlots (0x08)。
预载入协议模块socket服务组件载入协议协议模块的动作是动态进行的,当针对某一个协议的第一个socket被创建的时候,该协议模块在此时才会被载入。尽管如此,载入协议仍然是一件比较费时的操作,RSocketServ提供了一个StartProtocol()函数,来进行协议模块的预载入操作,调用该函数可以在socket连接请求的时候节省载入协议模块的时间。
如果你的应用程序需要在程序启动之初就载入协议模块,而并非需要连接的时候才进行载入,那么可以使用下面的函数范例来调用StartProtocol()方法:
void StartProtocol (TUint aFamily, TUint aSockType, TUint aProtocol, TRequestStatus& aStatus);
StartProtocol()函数的参数有:协议族(例如,KAfInet),使用该协议的socket类型(例如,KSockStream),协议族中的协议标示(例如,KProtocolInetTcp),最后一个参数是异步调用的完成状态参数。这些参数的意义将会在下面做以简短介绍。
请注意,尽管StartProtocol()函数是一个异步服务,但是它却是一个在操作过程中不能被取消的操作。
使用RSocket类RSocket代表了应用程序的一个socket连接,在一个应用程序中,每一个socket连接都是一个单独的RSocket的实例。事实上,客户端应用程序的代码中使用更多的是RSocket类而并不是RSocketServ类。
RSocket是一个提供了许许多多服务的体积庞大的类,这些服务包括:
连接到服务,无论作为客户端还是服务端设置或者查询自己的地址,或者查询远程地址从socket读取数据向socket写入数据其他更多...在打开任何socket之前,我们必须有一个激活了的RSocketServ会话。并且,在上述提到的任何服务进行操作之前,我们要确保socket是打开的。作为打开一个socket的一部分,RSocket这个子回话对象(见上文说明)需要同一个socket服务器进行连接,这个服务器就是一个RScoketServ类的实例。
下面的章节介绍了RSocket的各种函数,有了这些函数的介绍和帮助我们就可以写出基于socket通信的应用程序来。
主机解析服务什么是主机解析?在一个由计算机组成的网络里,独立的主机使用不同的地址格式来判断各自是谁,是什么。
例如,你的电子邮件有可能保存在一台主机当中,这台主机可能有一个可读的地址,比如pop3.freeserve.net。这个地址尽管对人来说是可读的、是一个具有一定意义的地址,但是对于网络上的计算机来说,并没有任何直接的用处。
当你的邮件客户端程序尝试下载你可能会收到的电子邮件的时候,你的电脑就会使用你的电子邮件服务器的地址(先前举例的pop3.freeserve.net)去进行查询,将他们相对应的数字网络地址查询出来。当获得了机器可读的数字网络地址,应用程序才可能建立起连接。在TCP/IP协议族中,地址解析转换是由域名解析服务(Domain Name Service, DNS)进行的。
地址解析服务的用处有两个。首先,它可以让计算机网络(在本例中指的是Internet)的用户可以使用一个直接的、有意义的、人们可以理解并且可以记住的的地址来指向某一个网络资源。也许你曾经见过这样的网络地址212.134.93.203、204.71.202.160,但是一般情况下也许你并不会使用这样的数字地址去访问网络,一般情况下你更多使用的是例如www.symbian.com或者www.yahoo.com这样的地址。
其次,这种将网络物理地址和用户记忆的网络资源地址进行分割的服务,达到了网络硬件层进行升级或者替换的情况下并不会影响到用户访问的目的。这种机制也从另外一种情况下帮助了大的网络服务提供商,比如微软公司的Hotmail服务,使这些运营商可以在世界各地部署本地服务器,从而让每一个用户获得更快的访问速度,无论用户是在西雅图或者别的任何地方。
使用RHostResolver类作为客户端API的一部分,socket服务组件提供了RHostResolver类,用这个类我们可以获得一个通用的主机地址解析服务,这项服务的内部会自己处理相应不同协议的主机地址解析的细节问题。如果我们针对TCP/IP协议族而言,那么RHostResolver类扮演的就是客户端与域名解析服务(DNS)之间进行通信的服务角色。
每一个不同的协议,都提供了自己的主机解析服务,这些服务是作为协议模块的一个标准部分实现的。这样的设计就使得客户端可以仅仅访问RHostResolver类,而并不需要关心socket使用的是哪一种协议。
RHostResolver接口提供了如下几种功能供客户端应用程序访问,他们是:
将一个数字网络地址转换为人所能识别的包含一定意义的文本表现形式将人读地址转换为相对应的机读数字地址读取或者设置本地设备的主机名的方法/函数就像是RSocket一样,RHostResolver类继承自RSubSessionBase。因此,要想使用RHostResolver类,客户端应用程序就必须先进行对socket服务组件的服务器的连接,这个服务组件的服务器就是一个RSocketServ类的实例。
RHostResolver类提供了许多主机地址解析服务的函数/方法,每一个函数都提供了两个版本的多态函数--同步和异步操作。
请注意,因为这是一个通用的主机地址解析接口,但是并不是所有的协议都提供了主机地址解析服务,所以有些协议可能并没有提供任何主机地址解析服务。
如果客户端应用程序尝试使用RHostResolver中的函数去对一个不支持主机地址解析服务的协议请求主机地址解析服务,那么将会得到错误代码KErrNotSupported。
在进行任何主机地址解析服务之前,我们要打开一个RHostResolver类的实例。正如前面所提到过的,因为主机解析服务类是一个子会话类,所以在调用RHostResolver::Open()函数之前,该子会话类必须关联一个socket服务组件的服务器会话对象实例。
TInt Open(RSocketServ& aSocketServer, TUint anAddrFamily, TUint aProtocol);
下一步,我们将会根据上面所示的函数原形,制定我们希望用哪个地址类型来解析的主机地址,地址类型应该是和传递给RSocket::Open()函数的参数一致的。
最后,我们还需要指定一个协议来进行主机地址解析服务。如果之前选择的地址类型是协议无关类型的,那么我们可以在这里指定KUndefinedProtocol。
其他的RHostResolver类提供的函数如下所示:
TInt GetByName(const TDesC& aName, TNameEntry& aResult); TInt GetByAddress(const TSockAddr& anAddr, TNameEntry& aResult); TInt GetHostName(TDes& aName); TInt SetHostName(const TDesC& aName); // sync only TInt Next(TNameEntry& aResult);
这些函数中的大多数都是可以见名知意的;不过Next()函数例外,我们来进行一些解释:对于有些协议来说,GetByName()和GetByAddress()函数可能会一次找到不止一个结果,比如地址假名被允许的时候。如果这样的话,我们就需要调用Next()函数来返回下一个地址结果。
http://wiki.forum.nokia.com/index.php/%E4%BD%BF%E7%94%A8Socket_API
2009年11月30日
原帖链接http://blog.sina.com.cn/s/blog_59fd7a6f0100fs8y.html~type=v5_one&label=rela_prevarticle
真正的源~http://wiki.forum.nokia.com/index.php/使用Socket_API
简介通过这篇文章我们想为大家带来一些Symbian操作系统的有关sockets API的基本介绍。 本文的读者应该是希望在他们的应用程序中增添socket通信功能的Symbian操作系统的开发者,本文不仅提供了理论介绍,同样给出了可供实践参考的代码范例。
本文包含的内容有:
概括介绍了有关socket通信的有关组件。概括介绍了socket服务架构以及使用两个主要API类RSocketServ和RSocket的使用。讨论了创建两个终端之间进行通信的过程。讨论了socket之间通信的不同模式:基于一串数据流的模式以及基于离散消息的模式。一个如何使用活动对象来进行socket连接的实践范例。有关Socket的服务构架本文的一个内容是介绍给大家如何将基于Socket服务的通信功能加入到应用程序中来。尽管如此,计算机通信系统乃是一个十分复杂的系统,本文介绍的基于socket服务的通信仍然是在一个相对比较高级的层次,没有深入底层探讨的话题和技术。要想让socket服务来发挥作用,许多底层支持软件将是必须的。
下图说明了socket服务组件在Symbian系统的通信子系统中的哪一层位置,扮演如何一个角色。
[b]Symbian OS通信系统组件[/b]
首先我们来考虑传输层协议。上图的Internet互联网协议和红外协议,从Symbian 6.0之后支持的蓝牙®无线通讯技术都在这一层中。
当我们谈到Internet协议时,我们其实包括了一个隐式的依赖动作,那就是向ISP(互联网服务提供商)进行拨号连接。因此,如图所示我们可以看到Symbian系统提供了拨号网络接入组件。而在本图中,最重要的的系统组件是电话通信服务组件。
最终,我们需要设计到一个硬件设备,有了硬件我们才可以在选定的网络环境中接收和发送数据。上图的核心部分就是使用Internet协议的拨号接入网络,并且显示了串行通信组件在整个通信系统扮演了如何的角色。串行通信服务组件通过特定的硬件设备驱动,完成了硬件设备与它周围环境的通信。
什么是socket?那么什么是socket呢? 用一句引自伯克利(Berkeley)UNIX关于socket实现的经典定义来回答就是“socket就是通信终端”。
那究竟是什么意思呢?
一个socket代表了一条通信‘通道’逻辑上的终端。而实际上讲,socket是物理网络地址和逻辑端口号的一个集合,而这个集合可以向另外一个位置的与他具有相同定义的socket进行数据传输。
因为socket是由机器地址和端口号来区分/识别的,那么在一个特定的计算机网络上,每一个socket都是以此方式被唯一识别的。这就使得应用程序可以唯一地去定位网络上的另外一个位置的socket。
注意:对于同一台机器上的两个socket,他们是完全具备彼此间进行通信的可能的;在这种情况下,两个socket具有相同的主机地址,但是他们拥有不同的端口号。
主机地址和端口号的组合,对于不同协议是不同的。在socket的经典应用中,网络通信使用的是IP(Internet Protocol)协议,但是实际上socket是支持很多其它协议的,对于这方面的信息稍后会提到。
正如我们将会看到的,不管我们选择怎样的通信协议(传输层),我们都可以使用同一种已成熟的socket API来实现通信。
协议模块如上文所述,socket的经典应用是在TCP/IP协议的计算机网络上,使两个逻辑端点之间展开通信活动。最著名的应用TCP/IP的计算机网络,当然就是Internet了。
绝大多数socket系统的实现都限定在了TCP/IP网络的通信上。
但是,Symbian系统的socket服务组件,就实现了更多的内容;不仅如此,它还为其他组件提供了支持模块插件协议的基础构架。这就使得Symbian公司和它的开发伙伴们大大延长了socket服务组件以及支持socket的应用程序的应用时间。
由于新协议和传输层的引入,支持了新的传输‘语言’或协议的协议组件,从而使得socket服务组件可以随之适应新的应用环境。
随着Symbian系统第五版的socket服务组件支持了TCP/IP和红外协议的稽核。在Symbian 6.0版的时候,就增加了蓝牙®无线技术和短信息服务插件。
协议模块其实就是标准的Symbian系统动态链接库(DLL)。他们都有共同的UID2--KUidProtocolModule(0x1000004A)来表示他们的类型,并且拥有特殊的扩展名*.PRT。
一个关于经典系统的方面,就是socket服务对PLP(Psion Link Protocol)协议也是支持的。PLP被用来进行Symbian系统的手机和运行Microsoft Windows的台式或笔记本计算机之间进行通信。PLP的一个应用就是Symbian Connnect - 目前的被用于名为‘PsiWin’的Psion计算机。
socket服务组件可以以两种方式加载协议模块:
最通常的做法就是,协议模块会在第一个使用该协议的socket被打开的时候进行加载。另外一种做法是,应用程序可以显式地加载协议模块。这种做法的一个好处就在于,当协议加载需要一个比较长的时间的时候,应用程序或用户可以得到相应的提示。使用这种方法调用的API在本文的后面将会进行讨论。要说明的几点:一个协议模块可以包含多种协议实现。比如,在TCPIP.PRT模块中,就包含了UDP、TCP、ICMP、IP以及DNS协议的实现。单个协议的实现可以通过位于\system\data\.的.esk文件进行映射。而每个协议模块都有一个.esk文件来指定该模块所包含的协议,以及每个协议在插件模块中所处的索引位置。
传输的独立性上文已经提到,socket服务组件的插件架构特性可以使得新的协议模块在任何时间被安装到一部Symbian系统的手机当中。
这个架构可以使得socket服务组件来实现独立传输层的概念。借助于提供一个通用的核心socket API接口,这种架构就可以处理所有一般性数据传输系统的需求,并且通过添加特定协议的协议模块,socket服务组件就可以被广大应用程序开发者来给自己的产品增添通信功能,从而省下了大量的开发通信子系统的时间。
随着时间的发展,新的协议逐步登上历史舞台,协议模块都将会为了适应socket接口而被重写。而应用程序开发者,他们只需要增添协议新近引入的属性或者动作,来支持新的协议即可,Socket服务组件便会使用新的协议,借助操作系统底层的通信组件,来完成通信机制,而并不会影响到上层应用程序开发者的接口和开发。
总而言之,socket服务组件可以让应用程序开发者在仅仅维护一套核心API接口的情况下,可以借助操作系统的通信子系统来使用多个协议,从而减少了自己的开发工作量以及开发时间。
“客户端-服务器”接口Symbian系统的一个特点就是它具有一个体积很小的微内核(micro-kernel),因此我们只能把必须和硬件设备交互以及进行主机控制的核心服务放在内核端运行。而另外许许多多的系统服务只能以用户模式的服务器线程的形式运行,通常被称为‘系统服务器’。
socket服务组件就是这些‘系统服务器’中的一个,第三方应用程序就借助公开的客户端API,通过该组件完成通信功能。其中最重要的四个类为:
[b]RSocketServer[/b]: 这个类是用来建立和socket服务组件之间的连接以及获取必要的资源的。在客户端-服务器架构的定义中,该类表示了应用程序与socket服务组件之间建立连接的会话。所有的其他客户端接口类,在使用中都需要一个被打开的本类的实例来进行操作。[b]RSocket[/b]: 这个类表示了一个socket连接。一个标准的应用程序可能会在不同时间的时候,拥有若干个RSocket的实例在同时进行操作。[b]RHostResolver[/b]: 这个类用来提供主机名称解析服务的接口。[b]RNetDatabase[/b]: 这个类用来提供网络数据库访问的接口。RSocket, RHostResolver & RNetDatabase 均表示了一个给定的应用程序与socket服务组件之间进行的会话下的子会话,而应用程序与socket服务组件之间的会话就是一个RSocketServer的实例。
sockets服务器的主要类socket服务组件提供了两个主类,供他的客户端访问内部的API。
[b]RSocketServ[/b]: 在每个应用程序线程中,只要需要连接socket请求,他就必须使用一个本类的实例,来为其他连接(会话)提供socket服务。[b]RSocket[/b]: 每一个需要使用socket的应用程序线程,同样也需要一个或多个RSocket对象,这些对象就是子会话了。下面的两个部分将会介绍会话和子会话类(RSocketServ 和 RSocket)的详细内容。
使用RSocketServ类RSocketServ类扮演了一个十分重要的角色,因为它是客户端应用程序与socket服务组建之间的连接会话。
但是,客户端应用程序并不直接使用这个类来进行数据的发送和接收,或者创建一个远程通信端点;要完成这些任务的话,使用的是RSocket类,这个类将会在稍后进行介绍。
RSocketServ可以让客户端应用程序来向socket服务组件发起一些查询,查询的内容包括服务器支持的协议个数以及支持哪些协议,每个支持协议的具体信息等等。
希望使用socket的客户端应用程序,都将需要自己创建一个RSocketServ类的实例对象,用这个对象来表示该客户端应用程序和socket服务之间的会话。每一个独立的socket连接,都是一个独立的RSocket类的实例对象。可以说,在一个客户端应用程序中,该程序的RSocketServ类对象就是所有的RSocket类对象的容器。
RSocketServ类的两个常用函数就是Connect()和StandardProtocol()。
建立一个连接到sockets服务的会话使用Connect()方法,应用程序就可以建立与socket服务之间的一个会话。它仅仅使用一个参数--该会话所提供的消息通道的个数。
TInt Connect (TUint aMessageSlots);
消息数参数被用来限定应用程序向socket服务所同时并发的异步操作的请求通道数。每一个同步请求都将占用一个消息通道,并且请求准备中的异步操作也将占用一个消息通道。
一个普通socket进行的读写通信操作,都是异步进行的,也就是说这样的操作要占用两个消息通道。如果socket也可以进行同步操作的话,那么我们其实并不需要指定过多的消息通道,因为同步操作的消息通道是由socket客户端-服务器框架来完成的。对于你的应用程序在同一个时间内会使用到多少个消息通道,这完全是由你来断定的,而在大多数情况下,我们要尽可能的减少同时请求的消息通道数。
如果我们不指定任何特定的值,那么系统会使用一个默认值作为消息通道个数的参数:KESockDefaultMessageSlots (0x08)。
预载入协议模块socket服务组件载入协议协议模块的动作是动态进行的,当针对某一个协议的第一个socket被创建的时候,该协议模块在此时才会被载入。尽管如此,载入协议仍然是一件比较费时的操作,RSocketServ提供了一个StartProtocol()函数,来进行协议模块的预载入操作,调用该函数可以在socket连接请求的时候节省载入协议模块的时间。
如果你的应用程序需要在程序启动之初就载入协议模块,而并非需要连接的时候才进行载入,那么可以使用下面的函数范例来调用StartProtocol()方法:
void StartProtocol (TUint aFamily, TUint aSockType, TUint aProtocol, TRequestStatus& aStatus);
StartProtocol()函数的参数有:协议族(例如,KAfInet),使用该协议的socket类型(例如,KSockStream),协议族中的协议标示(例如,KProtocolInetTcp),最后一个参数是异步调用的完成状态参数。这些参数的意义将会在下面做以简短介绍。
请注意,尽管StartProtocol()函数是一个异步服务,但是它却是一个在操作过程中不能被取消的操作。
使用RSocket类RSocket代表了应用程序的一个socket连接,在一个应用程序中,每一个socket连接都是一个单独的RSocket的实例。事实上,客户端应用程序的代码中使用更多的是RSocket类而并不是RSocketServ类。
RSocket是一个提供了许许多多服务的体积庞大的类,这些服务包括:
连接到服务,无论作为客户端还是服务端设置或者查询自己的地址,或者查询远程地址从socket读取数据向socket写入数据其他更多...在打开任何socket之前,我们必须有一个激活了的RSocketServ会话。并且,在上述提到的任何服务进行操作之前,我们要确保socket是打开的。作为打开一个socket的一部分,RSocket这个子回话对象(见上文说明)需要同一个socket服务器进行连接,这个服务器就是一个RScoketServ类的实例。
下面的章节介绍了RSocket的各种函数,有了这些函数的介绍和帮助我们就可以写出基于socket通信的应用程序来。
主机解析服务什么是主机解析?在一个由计算机组成的网络里,独立的主机使用不同的地址格式来判断各自是谁,是什么。
例如,你的电子邮件有可能保存在一台主机当中,这台主机可能有一个可读的地址,比如pop3.freeserve.net。这个地址尽管对人来说是可读的、是一个具有一定意义的地址,但是对于网络上的计算机来说,并没有任何直接的用处。
当你的邮件客户端程序尝试下载你可能会收到的电子邮件的时候,你的电脑就会使用你的电子邮件服务器的地址(先前举例的pop3.freeserve.net)去进行查询,将他们相对应的数字网络地址查询出来。当获得了机器可读的数字网络地址,应用程序才可能建立起连接。在TCP/IP协议族中,地址解析转换是由域名解析服务(Domain Name Service, DNS)进行的。
地址解析服务的用处有两个。首先,它可以让计算机网络(在本例中指的是Internet)的用户可以使用一个直接的、有意义的、人们可以理解并且可以记住的的地址来指向某一个网络资源。也许你曾经见过这样的网络地址212.134.93.203、204.71.202.160,但是一般情况下也许你并不会使用这样的数字地址去访问网络,一般情况下你更多使用的是例如www.symbian.com或者www.yahoo.com这样的地址。
其次,这种将网络物理地址和用户记忆的网络资源地址进行分割的服务,达到了网络硬件层进行升级或者替换的情况下并不会影响到用户访问的目的。这种机制也从另外一种情况下帮助了大的网络服务提供商,比如微软公司的Hotmail服务,使这些运营商可以在世界各地部署本地服务器,从而让每一个用户获得更快的访问速度,无论用户是在西雅图或者别的任何地方。
使用RHostResolver类作为客户端API的一部分,socket服务组件提供了RHostResolver类,用这个类我们可以获得一个通用的主机地址解析服务,这项服务的内部会自己处理相应不同协议的主机地址解析的细节问题。如果我们针对TCP/IP协议族而言,那么RHostResolver类扮演的就是客户端与域名解析服务(DNS)之间进行通信的服务角色。
每一个不同的协议,都提供了自己的主机解析服务,这些服务是作为协议模块的一个标准部分实现的。这样的设计就使得客户端可以仅仅访问RHostResolver类,而并不需要关心socket使用的是哪一种协议。
RHostResolver接口提供了如下几种功能供客户端应用程序访问,他们是:
将一个数字网络地址转换为人所能识别的包含一定意义的文本表现形式将人读地址转换为相对应的机读数字地址读取或者设置本地设备的主机名的方法/函数就像是RSocket一样,RHostResolver类继承自RSubSessionBase。因此,要想使用RHostResolver类,客户端应用程序就必须先进行对socket服务组件的服务器的连接,这个服务组件的服务器就是一个RSocketServ类的实例。
RHostResolver类提供了许多主机地址解析服务的函数/方法,每一个函数都提供了两个版本的多态函数--同步和异步操作。
请注意,因为这是一个通用的主机地址解析接口,但是并不是所有的协议都提供了主机地址解析服务,所以有些协议可能并没有提供任何主机地址解析服务。
如果客户端应用程序尝试使用RHostResolver中的函数去对一个不支持主机地址解析服务的协议请求主机地址解析服务,那么将会得到错误代码KErrNotSupported。
在进行任何主机地址解析服务之前,我们要打开一个RHostResolver类的实例。正如前面所提到过的,因为主机解析服务类是一个子会话类,所以在调用RHostResolver::Open()函数之前,该子会话类必须关联一个socket服务组件的服务器会话对象实例。
TInt Open(RSocketServ& aSocketServer, TUint anAddrFamily, TUint aProtocol);
下一步,我们将会根据上面所示的函数原形,制定我们希望用哪个地址类型来解析的主机地址,地址类型应该是和传递给RSocket::Open()函数的参数一致的。
最后,我们还需要指定一个协议来进行主机地址解析服务。如果之前选择的地址类型是协议无关类型的,那么我们可以在这里指定KUndefinedProtocol。
其他的RHostResolver类提供的函数如下所示:
TInt GetByName(const TDesC& aName, TNameEntry& aResult); TInt GetByAddress(const TSockAddr& anAddr, TNameEntry& aResult); TInt GetHostName(TDes& aName); TInt SetHostName(const TDesC& aName); // sync only TInt Next(TNameEntry& aResult);
这些函数中的大多数都是可以见名知意的;不过Next()函数例外,我们来进行一些解释:对于有些协议来说,GetByName()和GetByAddress()函数可能会一次找到不止一个结果,比如地址假名被允许的时候。如果这样的话,我们就需要调用Next()函数来返回下一个地址结果。
http://wiki.forum.nokia.com/index.php/%E4%BD%BF%E7%94%A8Socket_API