iOS 网络编程iOS 杂谈MacOS开发 技术集锦

CFNetwork(一)

2017-01-10  本文已影响318人  醉卧栏杆听雨声

CFNetwork Concepts

@官方文档翻译-李冰

@译文

CFNetwork给予你能力去全面的控制协议栈的底层和高性能的框架。它是BSD套接字的延伸扩展,标准套接字抽象API对对象提供简化的任务如FTP和HTTP服务器的连接和解析DNS主机。CFNetwork同时基于BSD套接字的物理和理论。

正如CFNetwork依赖于BSD套接字,还有一些Cocoa类依赖于CFNetwork(比如NSURL)。此外,在Web Kit是一组在窗口显示web内容的Cocoa类。这两个类都是高级类并且大部分实现网络协议的细节由自己实现。因此,在软件层的接口看起像图1-1。

图 1-1 OS X中的CFNetwork和其他的软件层

layers_2x.png

当使用CFNetwork

CFNetwork在BSD套接字之上有一些优点。它提供了run loop 集成,所以如果你的应用程序基于run loop,你可以不用在线程中实现使用网络协议。CFNetwork包含了一些不用自己实现细节的对象去帮助你使用网络协议。比如,用CFFTP API你可以不必实现去使用FTP协议的所有细节。如果你理解网络协议并且需要它们提供的底层控制但是不想去自己实现,CFNetwork可能是正确的选择。

使用CFNetwork代替基础层网络APIs有一些明显的优势。CFNetwork 更多的关注网络协议,而基础层APIs更多的关注数据访问,比如通过HTTP或FTP传输数据。尽管基础APIs提供了一些可配置性,但CFNetwork提供了更多可配置性。更多的基础网络类,阅读 URL Session Programming Guide

现在你了解了CFNetwork和其他的OS X网络APIs的关系,你可以准备开始去熟悉CFNetwork的API以及构成CFNetwork底层构造的两个API。

CFNetwork的底层构造

在学习CFNetwork的API之前,你必须首先了解CFNetwork最为多数的基础API。CFNetwork依赖于Core Foundation框架的两个API,CFSocket和CFStream。了解这些API是使用CFNetwork最基本的环节。

CFSocket API

套接字是网络通信最基本的层级。一个套接字的作用类似与打电话的方式。它允许你连接到另一个套接字(无论本地或者通过网络)并将数据发送到该套接字。

最常见的套接字抽象是BSD套接字。CFSocket就是BSD套接字的抽象。在非常小的开销上,CFSocket提供了BSD套接字所有的功能,并且它将套接字集成到run loop中。CFSocket没有限制基于流的套接字(比如TCP),它可能处理任何类型的套接字。

你可以从scratch使用CFSocketCreate函数,或者从BSD套接字使用CFSocketCreateWithNative函数创建一个CFSocket对象。然后,你 可以使用CFSocketCreateRunLoopSource 函数创建run-loop源并使用CFRunLoopAddSource 函数将套接字添加到run loop中。这将使你的CFSocket无论在何时接收到消息时回调函数都会被调用。

阅读 CFSocket Reference更多关于CFSocket API的信息.

CFStream API

读取和写入流提供了一个简单的从不同的媒体和独立的设备交换数据的方法。你可以为本地内存、文件或者网络(使用套接字)创建数据流,并且你可以使用流而不用一次性把所有数据加载到内存中。

一个流是在通信路径上连续传输的字节序列。流是单向路径,所以进行双向通信有必要使用输入(读)流和输出(写)流。除了基于文件的数据流以外,你不能在流中查找;一旦已提供或消耗流数据,则不能在从流中检索流数据。

CFStream是两个新的CFType对象提供了这些抽象流的API:CFReadStream和CFWriteStream。两种类型的流都遵从通常的Core Foundation API约定。更多关于Core Foundation类型的信息,阅读 Core Foundation Design Concepts.

CFStream基于CFSocket之上并且是CFHTTP和CFFTP的基础。就像你看到的图1-2,尽管CFStream不是CFNetwork最正式的部分,但是它几乎是所有CFNetwork的基础。

Figure 1-2 CFStream API structure

framework_layers_2x.png

你可以几乎以相同的方式使用读取和写入流作为你的UNIX文件描述符。首先,通过制定的流类型(内存,文件或者套接字)实例化流并且设置任何选项。下一步,打开流并且不限任何时长的读取或者写入。当流存在时,你可以通过它的属性获取流的信息。一个流的属性是关于流的所有信息,比如它的源和目的地,这些并不是正在实际读取或者写入数据的一部分。当你不再需要留,关闭并处理它。

CFStream读取或写入流的函数将暂停或者阻塞当前进程,直到至少有一个字节的数据可以被读取或写入。为了避免当流阻塞时尝试读取或写入,使用函数的异步版本并在run loop上调度流。当它有可能在读取和写入时调用你的回调函数而不会阻塞。

除此之外,CFStream具有Secure Sockets Layer (SSL)协议的内置支持。你可以设置一个包含流的SSL信息的字典,例如要求安全等级或者自签署证书。然后作为kCFStreamPropertySSLSettings属性传入你的流中使它成为一个SSL流。

这章 Working with Streams 描述怎样读写流。

CFNetwork API Concepts

了解CFNetwork框架,你需要去熟悉它的组成部分。CFNetwork框架分解成单独的API,每个都包含特定的网络协议。根据应用程序,这些API可以组合使用或者单独使用。大部分编程约定在API中很常见,所以去理解它们每一个都很重要的。

CFFTP API

CFFTP使得和FTP服务器通信变得更简单。使用CFFTP API,你可以创建FTP读取流(下载)和FTP写入流(上传)

一个FTP流像其他的CFNetwork流一样工作。例如,你可以调用CFReadStreamCreateWithFTPURL函数创建FTP读取流。然后任何时候你都可以调用CFReadStreamGetError函数检查流的状态。

通过在FTP流上设置属性,您可以根据其特定应用而调整流。例如,如果通过流连接的服务器需要一个用户名和密码,你需要设置适当的属性以便流可以正常的工作。更多的关于FTP不同有效的特性信息阅读 Setting up the Streams.

一个CFFTP流可以用于同步或异步。调用CFReadStreamOpen函数当FTP读取流被创建时打开了指定的FTP服务器连接。使用CFReadStreamRead函数从流中读取和规定读取流引用,CFReadStreamRef当FTP读取流被创建时被返回。CFReadStreamRead函数用FTP服务器输出填充缓存区。

更多使用CFFTP的信息, 见 Working with FTP Servers.

CFHTTP API

去发送和接收HTTP消息,使用CFHTTP API。就像CFFTP是FTP协议的抽象一样,CFHTTP是HTTP协议的一个抽象。

Hypertext Transfer Protocol (HTTP)是一个服务器和客户端之间的请求/响应协议。客户端创建一个请求消息。消息随后被序列化后,这一过程消息被转换成原始字节流。消息直到他们被序列化前不能被传输。随后消息发送到服务器。请求通常访问一个文件,比如网页。服务器响应,返回一个跟着消息的字符串。如果有必要这一过程会重复很多次。

去创建一个HTTP请求消息,你需要指定以下:

当消息被创建过后,并序列化。序列化之后,一个请求可能看起来像这样:

GET / HTTP/1.0\r\nUser-Agent: UserAgent\r\nContent-Length: 0\r\n\r\n

反序列化是序列化相反的过程。通过反序列化,从客户端或者服务器接受到的一个原始的字节流回复到原生的表示。CFNetwork提供所有函数,需要得到传入的消息类型(请求或响应),HTTP版本,URL,头,体,序列化的消息。

更多使用CFHTTP的有效示例 Communicating with HTTP Servers.

CFHTTPAuthentication API

如果你不用证书(或不正确的证书)发送一个HTTP请求到一个认证服务器,服务器返回一个授权质询(通常称为401或407响应)。CFHTTPAuthentication API提供授权证书去询问HTTP消息。CFHTTPAuthentication支持以下认证方案:

在新的OS X v10.4中支持持续请求的能力。在OS X v10.3每次请求质询,你都必须从新开始授权会话。现在,你持有每个服务CFHTTPAuthentication对象集。当你收到401或407响应,找到该服务器合适的对象和证书并应用它们。CFNetwork使用该对象存储的信息尽可能有效的处理请求。

在对持续性的要求支撑上,新版本的CFHTTPAuthentication提供更好的性能。更多怎样使用CFHTTPAuthentication的信息可在 Communicating with Authenticating HTTP Servers获得.

CFHost API

使用CFHost API去获得主机信息,包含主机名,地址和可达信息。请求主机信息的过程被称为调解。

使用CFHost就像使用CFStream一样:

创建一个CFHost对象。

开始调解CFHost对象。
检索地址,主机名或可达信息中的任意一个。

摧毁CFHost对象当你使用完后。
像所有CFNetwork一样,CFHost兼容IPv4和IPv6。使用CFHost,你可以写完全透明的代码处理IPv4和IPv6。

CFHost和其余的CFNetwork紧密结合。例如,有一个CFStream的函数叫CFStreamCreatePairWithSocketToCFHost直接从CFHost对象创建一个CFStream对象。
更多关于 CFHost 对象函数信息, 见 CFHost Reference.

CFNetServices API

如果你想你的应用程序使用Bonjour的注册服务或发现服务,使用CFNetService API。Bonjour是苹果实现的允许你发布、发现和解决网络服务的零配置网络(ZEROCONF)。

为了实现Bonjour,CFNetService API定义了三种对象类型:CFNetService, CFNetServiceBrowser, 和 CFNetServiceMonitor。
一个CFNetService对象代表一个网络服务,比如打印机或一个文件服务器。它包含了另一台计算机解析该服务器的所有信息,如名称、类型、域和端口号。CFNetServiceBrowser是一个用来发现域内的域和网络服务的对象。CFNetServiceMonitor对象是用来监测变化的CFNetService对象,比如在iChat的状态信息。

更全面的Bonjour信息, 见 Bonjour Overview. 更多关于使用 CFNetServices 和 实现 Bonjour的信息, 见 NSNetServices and CFNetServices Programming Guide.

CFNetDiagnostics API

连接到网络的应用程序依赖于一个稳定的连接。如果网络关闭,这将导致应用程序出现问题。采用CFNetDiagnostics API,用户可以自己诊断网络问题比如:

一旦网络错误被诊断到,CFNetDiagnostics指导用户解决问题。你也许已经看见过如果Safari连接到一个网站出现错误时CFNetDiagnostics的行动。
在图1-3中你可以看到CFNetDiagnostics助手

图 1-3 网络诊断助手

net_diagnostics_2x.png

通过提供CFNetDiagnostics在网络错误的环境下,你可以调用CFNetDiagnosticDiagnoseProblemInteractively函数去引导用户通过提示找到一个解决方案。此外,你可以使用CFNetDiagnostics给用户提供查询连接状态和提供统一错误信息。

怎样整合CFNetDiagnotics到你的应用程序见 Using Network Diagnostics. CFNetDiagnostics is a new API in OS X v10.4.


官方文档

CFNetwork Concepts

CFNetwork is a low-level, high-performance framework that gives you the ability to have detailed control over the protocol stack. It is an extension to BSD sockets, the standard socket abstraction API that provides objects to simplify tasks such as communicating with FTP and HTTP servers or resolving DNS hosts. CFNetwork is based, both physically and theoretically, on BSD sockets.

Just as CFNetwork relies on BSD sockets, there are a number of Cocoa classes that rely on CFNetwork (NSURL, for example). In addition, the Web Kit is a set of Cocoa classes to display web content in windows. Both of these classes are very high level and implement most of the details of the networking protocols by themselves. Thus, the structure of the software layers looks like the image in Figure 1-1.

Figure 1-1 CFNetwork and other software layers on OS X

layers_2x.png

When to Use CFNetwork

CFNetwork has a number of advantages over BSD sockets. It provides run-loop integration, so if your application is run loop based you can use network protocols without implementing threads. CFNetwork also contains a number of objects to help you use network protocols without having to implement the details yourself. For example, you can use FTP protocols without having to implement all of the details with the CFFTP API. If you understand the networking protocols and need the low-level control they provide but don't want to implement them yourself, then CFNetwork is probably the right choice.

There are a number of advantages of using CFNetwork instead of Foundation-level networking APIs. CFNetwork is focused more on the network protocols, whereas the Foundation-level APIs are focused more on data access, such as transferring data over HTTP or FTP. Although Foundation APIs do provide some configurability, CFNetwork provides a lot more. For more information on Foundation networking classes, read URL Session Programming Guide.

Now that you understand how CFNetwork interacts with the other OS X networking APIs, you're ready to become familiar with the CFNetwork APIs along with two APIs that form the infrastructure for CFNetwork.

CFNetwork Infrastructure

Before learning about the CFNetwork APIs, you must first understand the APIs which are the foundation for the majority of CFNetwork. CFNetwork relies on two APIs that are part of the Core Foundation framework, CFSocket and CFStream. Understanding these APIs is essential to using CFNetwork.

CFSocket API

Sockets are the most basic level of network communications. A socket acts in a similar manner to a telephone jack. It allows you to connect to another socket (either locally or over a network) and send data to that socket.

The most common socket abstraction is BSD sockets. CFSocket is an abstraction for BSD sockets. With very little overhead, CFSocket provides almost all the functionality of BSD sockets, and it integrates the socket into a run loop. CFSocket is not limited to stream-based sockets (for example, TCP), it can handle any type of socket.

You could create a CFSocket object from scratch using the CFSocketCreate function, or from a BSD socket using the CFSocketCreateWithNative function. Then, you could create a run-loop source using the function CFSocketCreateRunLoopSource and add it to a run loop with the function CFRunLoopAddSource. This would allow your CFSocket callback function to be run whenever the CFSocket object receives a message.

Read CFSocket Reference for more information about the CFSocket API.

CFStream API

Read and write streams provide an easy way to exchange data to and from a variety of media in a device-independent way. You can create streams for data located in memory, in a file, or on a network (using sockets), and you can use streams without loading all of the data into memory at once.

A stream is a sequence of bytes transmitted serially over a communications path. Streams are one-way paths, so to communicate bidirectionally an input (read) stream and output (write) stream are necessary. Except for file-based streams, you cannot seek within a stream; once stream data has been provided or consumed, it cannot be retrieved again from the stream.

CFStream is an API that provides an abstraction for these streams with two new CFType objects: CFReadStream and CFWriteStream. Both types of stream follow all of the usual Core Foundation API conventions. For more information about Core Foundation types, read Core Foundation Design Concepts.

CFStream is built on top of CFSocket and is the foundatio for CFHTTP and CFFTP. As you can see in Figure 1-2, even though CFStream is not officially part of CFNetwork, it is the basis for almost all of CFNetwork.

Figure 1-2 CFStream API structure

framework_layers_2x.png

You can use read and write streams in much the same way as you do UNIX file descriptors. First, you instantiate the stream by specifying the stream type (memory, file, or socket) and set any options. Next, you open the stream and read or write any number of times. While the stream exists, you can get information about the stream by asking for its properties. A stream property is any information about the stream, such as its source or destination, that is not part of the actual data being read or written. When you no longer need the stream, close and dispose of it.

CFStream functions that read or write a stream will suspend, or block, the current process until at least one byte of the data can be read or written. To avoid trying to read from or write to a stream when the stream would block, use the asynchronous version of the functions and schedule the stream on a run loop. Your callback function is called when it is possible to read and write without blocking.

In addition, CFStream has built-in support for the Secure Sockets Layer (SSL) protocol. You can set up a dictionary containing the stream's SSL information, such as the security level desired or self-signed certificates. Then pass it to your stream as the kCFStreamPropertySSLSettings property to make the stream an SSL stream.

The chapter Working with Streams describes how to use read and write streams.

CFNetwork API Concepts

To understand the CFNetwork framework, you need to be familiar with the building blocks that compose it. The CFNetwork framework is broken up into separate APIs, each covering a specific network protocol. These APIs can be used in combination, or separately, depending on your application. Most of the programming conventions are common among the APIs, so it's important to comprehend each of them.

CFFTP API

Communicating with an FTP server is made easier with CFFTP. Using the CFFTP API, you can create FTP read streams (for downloading) and FTP write streams (for uploading). Using FTP read and write streams you can perform functions such as:

By setting properties on FTP streams, you can adapt your stream for its particular application. For example, if the server that the stream is connecting to requires a user name and password, you need to set the appropriate properties so the stream can work properly. For more information about the different properties available to FTP streams read Setting up the Streams.

A CFFTP stream can be used synchronously or asynchronously. To open the connection with the FTP server that was specified when the FTP read stream was created, call the function CFReadStreamOpen. To read from the stream, use the CFReadStreamRead function and provide the read stream reference, CFReadStreamRef, that was returned when the FTP read stream was created. The CFReadStreamRead function fills a buffer with the output from the FTP server.

For more information on using CFFTP, see Working with FTP Servers.

CFHTTP API

To send and receive HTTP messages, use the CFHTTP API. Just as CFFTP is an abstraction for FTP protocols, CFHTTP is an abstraction for HTTP protocols.

Hypertext Transfer Protocol (HTTP) is a request/response protocol between a client and a server. The client creates a request message. This message is then serialized, a process that converts the message into a raw byte stream. Messages cannot be transmitted until they are serialized first. Then the request message is sent to the server. The request typically asks for a file, such as a webpage. The server responds, sending back a string followed by a message. This process is repeated as many times as is necessary.

To create an HTTP request message, you specify the following:

GET / HTTP/1.0\r\nUser-Agent: UserAgent\r\nContent-Length: 0\r\n\r\n

Deserialization is the opposite of serialization. With deserialization, a raw byte stream received from a client or server is restored to its native representation. CFNetwork provides all of the functions needed to get the message type (request or response), HTTP version, URL, headers, and body from an incoming, serialized message.

More examples of using CFHTTP are available in Communicating with HTTP Servers.

CFHTTPAuthentication API

If you send an HTTP request to an authentication server without credentials (or with incorrect credentials), the server returns an authorization challenge (more commonly known as a 401 or 407 response). The CFHTTPAuthentication API applies authentication credentials to challenged HTTP messages. CFHTTPAuthentication supports the following authentication schemes:

Basic
Digest
NT LAN Manager (NTLM)
Simple and Protected GSS-API Negotiation Mechanism (SPNEGO)
New in OS X v10.4 is the ability to carry persistency across requests. In OS X v10.3 each time a request was challenged, you had to start the authentication dialog from scratch. Now, you maintain a set of CFHTTPAuthentication objects for each server. When you receive a 401 or 407 response, you find the correct object and credentials for that server and apply them. CFNetwork uses the information stored in that object to process the request as efficiently as possible.

By carrying persistency across request, this new version of CFHTTPAuthentication provides much better performance. More information about how to use CFHTTPAuthentication is available in Communicating with Authenticating HTTP Servers.

CFHost API

You use the CFHost API to acquire host information, including names, addresses, and reachability information. The process of acquiring information about a host is known as resolution.

CFHost is used just like CFStream:

Create a CFHost object.
Start resolving the CFHost object.
Retrieve either the addresses, host names, or reachability information.
Destroy the CFHost object when you are done with it.
Like all of CFNetwork, CFHost is IPv4 and IPv6 compatible. Using CFHost, you could write code that handles IPv4 and IPv6 completely transparently.

CFHost is integrated closely with the rest of CFNetwork. For example, there is a CFStream function called CFStreamCreatePairWithSocketToCFHost that will create a CFStream object directly from a CFHost object. For more information about the CFHost object functions, see CFHost Reference.

CFNetServices API

If you want your application to use Bonjour to register a service or to discover services, use the CFNetServices API. Bonjour is Apple's implementation of zero-configuration networking (ZEROCONF), which allows you to publish, discover, and resolve network services.

To implement Bonjour the CFNetServices API defines three object types: CFNetService, CFNetServiceBrowser, and CFNetServiceMonitor. A CFNetService object represents a single network service, such as a printer or a file server. It contains all the information needed for another computer to resolve that server, such as name, type, domain and port number. A CFNetServiceBrowser is an object used to discover domains and network services within domains. And a CFNetServiceMonitor object is used to monitor a CFNetService object for changes, such as a status message in iChat.

For a full description of Bonjour, see Bonjour Overview. For more information about using CFNetServices and implementing Bonjour, see NSNetServices and CFNetServices Programming Guide.

CFNetDiagnostics API

Applications that connect to networks depend on a stable connection. If the network goes down, this causes problems with the application. By adopting the CFNetDiagnostics API, the user can self-diagnose network issues such as:

Once the network failure has been diagnosed, CFNetDiagnostics guides the user to fix the problem. You may have seen CFNetDiagnostics in action if Safari failed to connect to a website. The CFNetDiagnostics assistant can be seen in Figure 1-3.

Figure 1-3 Network diagnostics assistant

net_diagnostics_2x.png

By providing CFNetDiagnostics with the context of the network failure, you can call the CFNetDiagnosticDiagnoseProblemInteractively function to lead the user through the prompts to find a solution. Additionally, you can use CFNetDiagnostics to query for connectivity status and provide uniform error messages to the user.

To see how to integrate CFNetDiagnotics into your application read Using Network Diagnostics. CFNetDiagnostics is a new API in OS X v10.4.

上一篇下一篇

猜你喜欢

热点阅读