尝试《Java Network Programming 4ed》Chapter 11 Readiness Selection翻译

Readiness Selection

For network programming, the second part of the new I/O APIs is readiness selection, the ability to choose a socket that will not block when read or written. This is primarily of interest to servers, although clients running multiple simultaneous connections with several windows open—such as a web spider or a browser—can take advantage of it as well. In order to perform readiness selection, different channels are registered with a Selector object. Each channel is assigned a SelectionKey. The program can then ask the Selector object for the set of keys to the channels that are ready to perform the operation you want to perform without blocking.

对于网络编程,new IO API的第二部分是readiness selection,它拥有选择一个在读写时不阻塞的能力。尽管打开了多个窗口,运行了多个并行的连接的客服端也可以用上,比如网络爬虫或浏览器,但是主要是用在服务端上。为了运行readiness selection,不同的channel注册了一个selector对象。每个channel赋予了一个SelectionKey,然后程序可以访问selector对象得到channel的key集合,(你)可以在这些key上做些非阻塞的操作。

The Selector Class

The only constructor in Selector is protected. Normally, a new selector is created by invoking the static factory method Selector.open():

selector的唯一构造方法是protected。通常通过调用静态工厂方法Selector.open()来创建新的selector:

public static Selector open() throws IOException

The next step is to add channels to the selector. There are no methods in the Selector class to add a channel. The register() method is declared in the SelectableChannel class. Not all channels are selectable—in particular, FileChannels aren’t selectable—but all network channels are. Thus, the channel is registered with a selector by passing the selector to one of the channel’s register methods:
下一步是给selector添加channel。在selector里没有方法添加channel,(但是)SelectableChannel类声明了register()方法。不是所有channel都可以传入selector的——特别是FileChannels是不可以——但其他network channel是可以。因此,selector通过把selector传到channel的register方法里来注册channel的:

public final SelectionKey register(Selector sel, int ops)throws ClosedChannelException
public final SelectionKey register(Selector sel, int ops, Object att)throws ClosedChannelException

This approach feels backward to me, but it’s not hard to use. The first argument is the selector the channel is registering with. The second argument is a named constant from the SelectionKey class identifying the operation the channel is registering for. The SelectionKey class defines four named bit constants used to select the type of the operation:

对我来说这个方法是落后的,但不难使用。第一个参数是用来传入channel的selector。第二个参数是SelectionKey类的命名常量,不同常量表示channel的注册类型。SelectionKey定义了四个位常量来选择操作类型:

• SelectionKey.OP_ACCEPT
• SelectionKey.OP_CONNECT
• SelectionKey.OP_READ
• SelectionKey.OP_WRITE

These are bit-flag int constants (1, 2, 4, etc.). Therefore, if a channel needs to register for multiple operations in the same selector (e.g., for both reading and writing on a socket), combine the constants with the bitwise or operator (|) when registering:

因为有多个位常量(1,2,4等),所以如果同一个selector需要给channel注册多个操作类型(比如在一个socket读和写),注册时操作类型按位来组合常量或使用|操作符来计算:

channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);

The optional third argument is an attachment for the key. This object is often used to store state for the connection. For example, if you were implementing a web server, you might attach a FileInputStream or FileChannel connected to the local file the server streams to the client. After the different channels have been registered with the selector, you can query the selector at any time to find out which channels are ready to be processed. Channels may be ready for some operations and not others. For instance, a channel could be ready for reading but not writing. There are three methods that select the ready channels. They differ in how long they wait to find a ready channel. The first, selectNow(), performs a nonblocking select. It returns immediately if no connections are ready to be processed now:
第三个参数是key的附属对象,通常用来存储连接的状态。比如,你正在实现一个网络服务器,你可以附加一个FileInputStream或者FileChannel的本地文件或服务端到客户端的流。在selector注册了不同的channel后,你可以在任何时候查询selector,从而知道哪个channel可以处理。channel对有些操作是做好准备有些不然。比如,channel可读不可写。有三个方法可以选择做好准备的channel。他们的区别是获取准备好的channel所用到的等待时间。第一,selectNow()是非阻塞,如果没有连接可供处理就会迅速返回。

public abstract int selectNow() throws IOException

The other two select methods are blocking:

其他两个select方法是阻塞的:

public abstract int select() throws IOException
public abstract int select(long timeout) throws IOException

The first method waits until at least one registered channel is ready to be processed before returning. The second waits no longer than timeout milliseconds for a channel to be ready before returning 0. These methods are useful if your program doesn’t have anything to do when no channels are ready to be processed. When you know the channels are ready to be processed, retrieve the ready channels using selectedKeys():

第一个方法在返回前如果没有channel可供处理会一直等待。第二个方法在等待channel超出超时时间后返回0。这些方法对没有channel可供处理时没有任何操作的程序有用。当你知道channel可以被处理了,用selectedKeys()获取该channel。

public abstract Set<SelectionKey> selectedKeys()

You iterate through the returned set, processing each SelectionKey in turn. You’ll also want to remove the key from the iterator to tell the selector that you’ve handled it. Otherwise, the selector will keep telling you about it on future passes through the loop. Finally, when you’re ready to shut down the server or when you no longer need the selector, you should close it:

你遍历了返回的结合,轮流处理每个SelectionKey。也许你还要从iterator中移除key,告诉selector你已经处理了它。否则,selector会在将来的循环中一直告诉你它的存在。最后当你准备关闭服务器或不在需要selector,应该关闭它:

public abstract void close() throws IOException

This step releases any resources associated with the selector. More importantly, it cancels all keys registered with the selector and interrupts up any threads blocked by one of this selector’s select methods.

这一步释放了所有和selector有关的资源。更重要的是,它删除了selector注册的所有key并打断所有被selector的select方法阻塞的线程。

The SelectionKey Class

SelectionKey objects serve as pointers to channels. They can also hold an object attachment, which is how you normally store the state for the connection on that channel. SelectionKey objects are returned by the register() method when registering a channel with a selector. However, you don’t usually need to retain this reference. The selectedKeys() method returns the same objects again inside a Set. A single channel can be registered with multiple selectors. When retrieving a SelectionKey from the set of selected keys, you often first test what that key is ready to do. There are four possibilities:

SelectionKey对象作为channel的指针,也可以持有附属对象,在附属对象上存储channel连接的状态。当selector注册了一个channel,register()会返回SelectionKey对象。但是你不必保留这个引用,selectedKeys()再次返回集合里相同的对象,单个channel可以在多个selector上注册。当从selected key集合里获取SelectionKey,你经常会首先判断那种key可以用,(这)有四种可能:

public final boolean isAcceptable()
public final boolean isConnectable()
public final boolean isReadable()
public final boolean isWritable()

This test isn’t always necessary. In some cases, the selector is only testing for one possibility and will only return keys to do that one thing. But if the selector does test for multiple readiness states, you’ll want to test which one kicked the channel into the ready state before operating on it. It’s also possible that a channel is ready to do more than one thing. Once you know what the channel associated with the key is ready to do, retrieve the channel with the channel() method:

判断不总是需要的。在一些情况下,判断selector只有一种情况并且对返回的key只做一件事。但是如果selector判断多种readiness状态,你会想要在操作前判断哪一个channel匹配上状态。也有可能一个channel是准备做多件事情,一旦你知道那个channel和key相关,那就调用channel()方法获取channel:

public abstract SelectableChannel channel()

If you’ve stored an object in the SelectionKey to hold state information, you can retrieve it with the attachment() method:

如果你在SelectionKey存储了一个存有状态信息的对象,你可以通过attachment()方法获取它:

public final Object attachment()
Finally, when you’re finished with a connection, deregister its SelectionKey object so the selector doesn’t waste any resources querying it for readiness. I don’t know that this is absolutely essential in all cases, but it doesn’t hurt. You do this by invoking the key’s

cancel() method:
最后你利用完连接,要撤销注册SelectionKey对象以便selector在查询时不会浪费资源。我不知道是不是在所有情况下都有绝对必要这么做,但也没坏处。调用cancel()就干了吧:

public abstract void cancel()
However, this step is only necessary if you haven’t closed the channel. Closing a channel automatically deregisters all keys for that channel in all selectors. Similarly, closing a selector invalidates all keys in that selector.
然而,如果channel还没有关闭,这一步才是必要。关闭channel将会自动撤销在selector里注册的所有channel的key。类似的,关闭selector会是selector里的所有key作废。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值