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

来源:互联网 发布:易观智库外卖数据 编辑:程序博客网 时间:2024/05/01 15:28

Channels

Channels move blocks of data into and out of buffers to and from various I/O sources such as files, sockets, datagrams, and so forth. The channel class hierarchy is rather convoluted, with multiple interfaces and many optional operations. However, for purposes of network programming there are only three really important channel classes, SocketChannel, ServerSocketChannel, and DatagramChannel; and for the TCP connections we’ve talked about so far you only need the first two.

channel将大块的数据从IO数据源,诸如file,socket,datagrams等等转移到buffer或从buffer转出。channel的类层级是相当复杂的,有个多个接口和许多的可选的操作。不过在网络编程上,只有三个相当重要的channel类,SocketChannel, ServerSocketChannel, 和 DatagramChannel。TCP连接我们目前为止讲了不少,你只需要(学习)前两个。

SocketChannel

The SocketChannel class reads from and writes to TCP sockets. The data must be encoded in ByteBuffer objects for reading and writing. Each SocketChannel is associated with a peer Socket object that can be used for advanced configuration, but this requirement can be ignored for applications where the default options are fine.

SocketChannel类在TCP socket读写。为了读写(数据)ByteBuffer对象的数据必须是已编码的。每个SocketChannel和一个socket对象相互联系,socket有高级配置选项,但是如果默认配置对应用来说够用的话那么可以忽略它。

connecting

The SocketChannel class does not have any public constructors. Instead, you create a new SocketChannel object using one of the two static open() methods:

SocketChannel类没有公用构造方法,反而你可以用两个静态的open()方法之一来创建一个新的SocketChannel。

public static SocketChannel open(SocketAddress remote) throws IOExceptionpublic static SocketChannel open() throws IOException

The first variant makes the connection. This method blocks (i.e., the method will not return until the connection is made or an exception is thrown). For example:

第一个方法变体创建了连接,这个方法是阻塞的(就是说这方法要等到连接成功或者异常抛出才返回),比如:

SocketAddress address = new InetSocketAddress("www.cafeaulait.org", 80);SocketChannel channel = SocketChannel.open(address);

The noargs version does not immediately connect. It creates an initially unconnected socket that must be connected later using the connect() method. For example:

没有参数的方法不会立即连接,它会创建一个初始化了的未连接的socket,此后必须用connet()方法来连接。比如:

SocketChannel channel = SocketChannel.open();SocketAddress address = new InetSocketAddress("www.cafeaulait.org", 80);channel.connect(address);

You might choose this more roundabout approach in order to configure various options on the channel and/or the socket before connecting. Specifically, use this approach if you want to open the channel without blocking:

也许你选择这个迂回的方法来在连接前配置各种channel或socket选项。你要明确(知道)如果你想要无阻塞地打开这个channel那就用这个方法:

SocketChannel channel = SocketChannel.open();SocketAddress address = new InetSocketAddress("www.cafeaulait.org", 80);channel.configureBlocking(false);channel.connect();

With a nonblocking channel, the connect() method returns immediately, even before the connection is established. The program can do other things while it waits for the operating system to finish the connection. However, before it can actually use the connection, the program must call finishConnect():

即便在连接建立前,使用非阻塞channel的connect()方法会立刻返回。程序可以在等待操作系统完成连接的时候做其他事情。但是在连接实际可用前,程序必须调用finishConnect():

public abstract boolean finishConnect() throws IOException 

(This is only necessary in nonblocking mode. For a blocking channel, this method returns true immediately.) If the connection is now ready for use, finishConnect() returns true. If the connection has not been established yet, finishConnect() returns false. Finally, if the connection could not be established, for instance because the network is down, this method throws an exception. If the program wants to check whether the connection is complete, it can call these two methods:

(只有在非阻塞模式下才是必须的,对于阻塞channel方法会立刻返回) 如果连接现可以投入使用,finishConnect()返回true。如果连接还未建立,finishConnect()返回false。最后,如果连接未建立,例如网络关闭,这个方法会抛出异常。如果程序想检查连接是否完成,可以调用这两个方法:

public abstract boolean isConnected()public abstract boolean isConnectionPending()
The isConnected() method returns true if the connection is open. The isConnectionPending() method returns true if the connection is still being set up but is not yet open.
如果连接打开了,isConnected()方法返回true。连接正在设置未打开的话isConnectionPending()返回true。

reading

To read from a SocketChannel, first create a ByteBuffer the channel can store data in. Then pass it to the read() method:

首先创建一个channel能存储数据的ByteBuffer来读取SocketChannel,然后将它传入read()方法:

public abstract int read(ByteBuffer dst) throws IOException
The channel fills the buffer with as much data as it can, then returns the number of bytes it put there. When it encounters the end of stream, the channel fills the buffer with any remaining bytes and then returns –1 on the next call to read(). If the channel is blocking, this method will read at least one byte or return –1 or throw an exception. If the channel is nonblocking, however, this method may return 0.Because the data is stored into the buffer at the current position, which is updated automatically as more data is added, you can keep passing the same buffer to the read() method until the buffer is filled. For example, this loop will read until the buffer is filled or the end of stream is detected:

channel会给buffer填充可能多的数据,返回它存放的字节数。遇上了stream结尾,channel将会把剩余的字节填入,在下次调用read()返回-1。如果channel阻塞,它会读取至少一个字节或返回-1或抛出异常。如果channel非阻塞,它会返回0。因为数据存储在buffer的当前position(游标)下,数据再添加进来游标就会自动更新,所以在buffer填满前你可以持续传同一个buffer到read()方法。比如,下面的循环会一直读直到buffer填满后或者stream检测到结尾。

while (buffer.hasRemaining() && channel.read(buffer) != -1) ;

It is sometimes useful to be able to fill several buffers from one source. This is called a scatter. These two methods accept an array of ByteBuffer objects as arguments and fill each one in turn:

从一个数据源填满多个buffer有时是很有用。这叫做scatter。这两个方法接收一个ByteBuffer对象数组作为参数并填满每个buffer。

public final long read(ByteBuffer[] dsts) throws IOExceptionpublic final long read(ByteBuffer[] dsts, int offset, int length) throws IOException

The first variant fills all the buffers. The second method fills length buffers, starting with the one at offset. To fill an array of buffers, just loop while the last buffer in the list has space remaining. For example:

第一个方法填满所有buffer,第二个方法填满指定长度,起始位置的buffer。为了填满数组里的所有buffer,只要最后一个buffer还包含数据就一直循环,比如:

ByteBuffer[] buffers = new ByteBuffer[2];buffers[0] = ByteBuffer.allocate(1000);buffers[1] = ByteBuffer.allocate(1000);while (buffers[1].hasRemaining() && channel.read(buffers) != -1) ;

writing

Socket channels have both read and write methods. In general, they are full duplex. In order to write, simply fill a ByteBuffer, flip it, and pass it to one of the write methods, which drains it while copying the data onto the output—pretty much the reverse of the reading process. The basic write() method takes a single buffer as an argument:

Socket channel都有读写方法,一般来说,他们是双工的(不知怎么翻译)。填满ByteBuffer,flip它,将它传如一个消耗buffer数据的同时将数据复制到输出的写方法就完成写操作---和读的过程完全相反。write()基础方法有一个简单的buffer参数。

public abstract int write(ByteBuffer src) throws IOException

As with reads (and unlike OutputStreams), this method is not guaranteed to write the complete contents of the buffer if the channel is nonblocking. Again, however, the cursor-based nature of buffers enables you to easily call this method again and again until the buffer is fully drained and the data has been completely written:

就像读一样(不像OutputStreams),如果过channel非阻塞,那么这个方法不能保证写完buffer的所有内容。再次,基于游标的buffer使你很容易多次调用这个方法直到buffer完全被消费了,数据完全写入了。

while (buffer.hasRemaining() && channel.write(buffer) != -1) ;

It is often useful to be able to write data from several buffers onto one socket. This is called a gather. For example, you might want to store the HTTP header in one buffer and the HTTP body in another buffer. The implementation might even fill the two buffers simultaneously using two threads or overlapped I/O. These two methods accept an array of ByteBuffer objects as arguments, and drain each one in turn:

将多个buffer写入socket是很有用的,这称之为gather。比如,你可能要吧http头部存在一个buffer,http体存在其他buffer,甚至可以实现为用两个线程或overlapped I/O同时填满两个buffer。这两个方法接收一个ByteBuffer对象数组作为参数,轮流消费buffer。

public final long write(ByteBuffer[] dsts) throws IOExceptionpublic final long write(ByteBuffer[] dsts, int offset, int length) throws IOException

The first variant drains all the buffers. The second method drains length buffers, starting with the one at offset.

第一个方法消费所有buffer,第二个方法消费定长的,指定起始位置的buffer。

closing

Just as with regular sockets, you should close a channel when you’re done with it to free up the port and any other resources it may be using:

和常规的socket一样,在你处理完所有事情释放端口和其他使用到的资源时应该关闭channel:

public void close() throws IOException

Closing an already closed channel has no effect. Attempting to write data to or read data from a closed channel throws an exception. If you’re uncertain whether a channel has been closed, check with isOpen():

关闭一个已经关闭的channel是无效的。尝试对已关闭的channel读写会抛出异常。如果你不确保channel是否已关闭那么可以用isOPen()检查:

public boolean isOpen()

Naturally, this returns false if the channel is closed, true if it’s open (close() and isOpen() are the only two methods declared in the Channel interface and shared by all channel classes). Starting in Java 7, SocketChannel implements AutoCloseable, so you can use it in trywith-resources.

如果channel已关闭这个方法很自然地返回false,反之返回true(close() 和isOpen()是Channel接口声明的仅有的两个方法,所有的channel类都有它们)。从java7开始,SocketChannel实现了AutoCloseable,你可以在trywith-resources代码块使用它。

ServerSocketChannel

The ServerSocketChannel class has one purpose: to accept incoming connections. You cannot read from, write to, or connect a ServerSocketChannel. The only operation it supports is accepting a new incoming connection. The class itself only declares four methods, of which accept() is the most important. ServerSocketChannel also inherits several methods from its superclasses, mostly related to registering with a Selector for notification of incoming connections. And finally, like all channels, it has a close() method that shuts down the server socket.

ServerSocketChannel类只有一个目的:接收连接。你不能从中读写或连接一个ServerSocketChannel,唯一的操作是接收新到来的连接。这个类声明了四个方法,accept()是最重要的方法。ServerSocketChannel也继承了超类的几个方法,大都和注册selector来实现连接通知相关。最后,像channel那样,它有个关闭服务端socket的close()方法。

Creating server socket channels

The static factory method ServerSocketChannel.open() creates a new ServerSocketChannel object. However, the name is a little deceptive. This method does not actually open a new server socket. Instead, it just creates the object. Before you can use it, you need to call the socket() method to get the corresponding peer ServerSocket. At this point, you can configure any server options you like, such as the receive buffer size or the socket timeout, using the various setter methods in ServerSocket. Then connect this ServerSocket to a SocketAddress for the port you want to bind to. For example, this code fragment opens a ServerSocketChannel on port 80:

静态方法ServerSocketChannel.open()创建一个新的ServerSocketChannel对象。但是,容易被它的名字所迷惑。实际上这个方法并没有创建一个新的服务端soket,反而它仅仅创建一个对象。使用前你要调用socket()方法获取相关的ServerSocket。在这时,你可以配置你喜欢的服务器选项,比如用ServerSocket的各种设置方法接收到的buffer大小。socket超时时间。然后把ServerSocket连到你想要绑定的SocketAddress的端口。比如,下面的代码片段在80端口打开了ServerSocketChannel:

try { ServerSocketChannel server = ServerSocketChannel.open(); ServerSocket socket = serverChannel.socket(); SocketAddress address = new InetSocketAddress(80); socket.bind(address);} catch (IOException ex) { System.err.println("Could not bind to port 80 because " + ex.getMessage());}

In Java 7, this gets a little simpler because ServerSocketChannel now has a bind() method of its own:

java 7里,这段代码会更变得简单,因为ServerSocketChannel如今有了他自己的bind()方法:

try { ServerSocketChannel server = ServerSocketChannel.open(); SocketAddress address = new InetSocketAddress(80); server.bind(address);} catch (IOException ex) { System.err.println("Could not bind to port 80 because " + ex.getMessage());}

A factory method is used here rather than a constructor so that different virtual machines can provide different implementations of this class, more closely tuned to the local hardware and OS. However, this factory is not user configurable. The open() method always returns an instance of the same class when running in the same virtual machine.

这里用工厂方法不用构造方法以便不同的虚拟机能提供不同的(ServerSocketChannel)类的实现,(从而)更好的适应本地硬件和操作系统。但是工厂方法不能配置。open()方法总是返回一个在相同虚拟机上运行的相同类的实例。

Accepting connections

Once you’ve opened and bound a ServerSocketChannel object, the accept() method can listen for incoming connections:

一旦你打开,包装了ServerSocketChannel对象,accept()方法会监听到来的连接:

public abstract SocketChannel accept() throws IOException

accept() can operate in either blocking or nonblocking mode. In blocking mode, the accept() method waits for an incoming connection. It then accepts that connection and returns a SocketChannel object connected to the remote client. The thread cannot do anything until a connection is made. This strategy might be appropriate for simple servers that can respond to each request immediately. Blocking mode is the default. A ServerSocketChannel can also operate in nonblocking mode. In this case, the accept() method returns null if there are no incoming connections. Nonblocking mode is more appropriate for servers that need to do a lot of work for each connection and thus may want to process multiple requests in parallel. Nonblocking mode is normally used in conjunction with a Selector. To make a ServerSocketChannel nonblocking, pass false to its configureBlocking() method. The accept() method is declared to throw an IOException if anything goes wrong. There are several subclasses of IOException that indicate more detailed problems, as well as a couple of runtime exceptions:

accept()可以在阻塞和非阻塞下使用。在阻塞模式下,accept()方法等待一个到来的连接,然后接受连接返回一个连接了远程客户端的SocketChannel对象。(本)线程在连接建立前不能做任何事。对能快速对每个请求做出反应的简单服务器来说这个策略也许是合适的。默认是阻塞的,(而且)ServerSocketChannel可以在非阻塞下操作。在这种情况下,如果没有连接到来accept()方法会返回null。非阻塞模式更加适合对每个连接(请求)做很多事情的服务器,这样就可以并行处理多个请求。非阻塞模式下经常和selector配合使用。configureBlocking()传入false可以使让ServerSocketChannel是非阻塞。出错时accept()方法会抛出异常。有几个IOException子类和运行时异常来说明更详细的问题:

ClosedChannelException

You cannot reopen a ServerSocketChannel after closing it.

你不能重新打开一个已关闭的ServerSocketChannel

AsynchronousCloseException

Another thread closed this ServerSocketChannel while accept() was executing.

其他线程关闭了ServerSocketChannel而accept()正在运行

ClosedByInterruptException

Another thread interrupted this thread while a blocking ServerSocketChannel was waiting.

其他线程打断本线程而阻塞的ServerSocketChannel还在等待

NotYetBoundException

You called open() but did not bind the ServerSocketChannel’s peer ServerSocket to an address before calling accept(). This is a runtime exception, not an IOException.

再调用accept()强你调用了open(),但是没有绑定ServerSocketChannel的ServerSocket到一个地址。只是运行时异常,不适IO异常

SecurityException

The security manager refused to allow this application to bind to the requested port.

安全管理机制拒绝应用绑定请求端口

The Channels Class

Channels is a simple utility class for wrapping channels around traditional I/O-based streams, readers, and writers, and vice versa. It’s useful when you want to use the new I/O model in one part of a program for performance, but still interoperate with legacy APIs that expect streams. It has methods that convert from streams to channels and methods that convert from channels to streams, readers, and writers:

channel只是封装了基于传统IO stream,reader,writer的channel的简单工具类,反之亦然(不明白什么意思)。你用了new IO模型作为你程序的一部分将对(提高)性能很有益处,不过它依然和以前遗留的stream的API有交互(不知道翻译对不)。它有把stream转成channel,把channel装成stream,reader,writer的方法。

public static InputStream newInputStream(ReadableByteChannel ch)public static OutputStream newOutputStream(WritableByteChannel ch)public static ReadableByteChannel newChannel(InputStream in)public static WritableByteChannel newChannel(OutputStream out)public static Reader newReader (ReadableByteChannel channel, CharsetDecoder decoder, int minimumBufferCapacity)public static Reader newReader (ReadableByteChannel ch, String encoding)public static Writer newWriter (WritableByteChannel ch, String encoding)
The SocketChannel class discussed in this chapter implements both the ReadableByteChannel and WritableByteChannel interfaces seen in these signatures. ServerSocketChannel implements neither of these because you can’t read from or write to it. For example, all current XML APIs use streams, files, readers, and other traditional I/O APIs to read the XML document. If you’re writing an HTTP server designed to process SOAP requests, you may want to read the HTTP request bodies using channels and parse the XML using SAX for performance. In this case, you’d need to convert these channels into streams before passing them to XMLReader’s parse() method:

本章讨论的SocketChannel实现了ReadableByteChannel和WritableByteChannel 接口(seen in these signatures没翻译)。ServerSocketChannel没对两个接口实现是因为你无法对他读写。比如,现有的XML API使用了stream,file,reader和其他的传统IO API来读取XML文档。如果你写了一个http服务端用来处理SOAP请求,你也许会用channel读请求体,SAX来有效率地解析XML。这样的话,在将他们传入XMLReader的parse()方法你必须把channel转成stream。

SocketChannel channel = server.accept();processHTTPHeader(channel);XMLReader parser = XMLReaderFactory.createXMLReader();parser.setContentHandler(someContentHandlerObject);InputStream in = Channels.newInputStream(channel);parser.parse(in);

Asynchronous Channels (Java 7)

Java 7 introduces the AsynchronousSocketChannel and AsynchronousServerSocketChannel classes. These behave like and have almost the same interface as SocketChannel and ServerSocketChannel (though they are not subclasses of those classes). However, unlike SocketChannel and ServerSocketChannel, reads from and writes to asynchronous channels return immediately, even before the I/O is complete. The data read or written is further processed by a Future or a CompletionHandler. The connect() and accept() methods also execute asynchronously and return Futures. Selectors are not used. For example, suppose a program needs to perform a lot of initialization at startup. Some of that involves network connections that are going to take several seconds each. You can start several asynchronous operations in parallel, then perform your local initializations, and then request the results of the network operations:

java7引入了AsynchronousSocketChannel和AsynchronousServerSocketChannel类。他们像接口SocketChannel,ServerSocketChannel一样的运作(尽管不是它们的子类)。但是,和SocketChannel,ServerSocketChannel不一样的是,即便IO未完成,对异步channel读写且很快返回。数据的进一步读写是依靠Future和CompletionHandler。connect()和accept()也是异步执行并返回Future,没有用到selector。比如,假设有个程序需要在启动时做很多初始化的工作,有些工作调用到网络连接并且每个连接花费数秒。你可以并行地开始这些异步操作,然后做你的本地初始化,再请求网络操作的结果。

SocketAddress address = new InetSocketAddress(args[0], port);AsynchronousSocketChannel client = AsynchronousSocketChannel.open();Future<Void> connected = client.connect(address);ByteBuffer buffer = ByteBuffer.allocate(74);// wait for the connection to finishconnected.get();// read from the connectionFuture<Integer> future = client.read(buffer);// do other things...// wait for the read to finish...future.get();// flip and drain the bufferbuffer.flip();WritableByteChannel out = Channels.newChannel(System.out);out.write(buffer);
The advantage of this approach is that the network connections run in parallel while the program does other things. When you’re ready to process the data from the network, but not before, you stop and wait for it by calling Future.get(). You could achieve the same effect with thread pools and callables, but this is perhaps a little simpler, especially if buffers are a natural fit for your application. This approach fits the situation where you want to get results back in a very particular order. However, if you don’t care about order, if you can process each network read independently of the others, then you may be better off using a CompletionHandler instead. For example, imagine you’re writing a search engine web spider that feeds pages into some backend. Because you don’t care about the order of the responses returned, you can spawn a large number of AsynchronousSocketChannel requests and give each one a CompletionHandler that stores the results in the backend. The generic CompletionHandler interface declares two methods: completed(), which is invoked if the read finishes successfully; and failed(), which is invoked on an I/O error. For example, here’s a simple CompletionHandler that prints whatever it received on System.out:

这方法的优点是网络连接是并行,同时程序可以处理其他事情。当你准备处理来自网络的数据,而不是之前(译者不明白),你停下并调用Future.get()等待数据。尽管用线程池和callable也能取得同样效果,但是这样做也许会更简单,特别适合你的应用里结合了buffer使用。这个方法满足了你想要以一个特别的顺序来获取结果的场景。然而如果你并不关心响应的返回的顺序,你可以产生大量AsynchronousSocketChannel请求,赋予每个请求一个CompletionHandler来在后端做存储。泛型接口CompletionHandler声明两个方法:completed(),读取成功时调用,failed(),IO有错误时调用。比如,这里有个简单的CompletionHandler用来打印从System.out接收到的所有数据:

class LineHandler implements CompletionHandler<Integer, ByteBuffer> { @Override public void completed(Integer result, ByteBuffer buffer) {  buffer.flip();  WritableByteChannel out = Channels.newChannel(System.out);  try {   out.write(buffer);  } catch (IOException ex) {   System.err.println(ex);  } } @Override public void failed(Throwable ex, ByteBuffer attachment) {  System.err.println(ex.getMessage()); }}
When you read from the channel you pass a buffer, an attachment, and a CompletionHandler to the read() method:

在你读取channel时传入一个buffer,一个attachment和一个CompletionHandler到read()方法:

ByteBuffer buffer = ByteBuffer.allocate(74);CompletionHandler<Integer, ByteBuffer> handler = new LineHandler();channel.read(buffer, buffer, handler);
Here I’ve made the attachment the buffer itself. This is one way to push the data read from the network into the CompletionHandler where it can handle it. Another common pattern is to make the CompletionHandler an anonymous inner class and the buffer a final local variable so it’s in scope inside the completion handler. Although you can safely share an AsynchronousSocketChannel or AsynchronousServerSocketChannel between multiple threads, no more than one thread can read from this channel at a time and no more than one thread can write to the channel at a time. (One thread can read and another thread can write simultaneously, though.) If a thread attempts to read while another thread has a pending read, the read() method throws a ReadPendingException. Similarly, if a thread attempts to write while another thread has a pending write, the write() method throws a WritePendingException.

这里的attachment是buffer自身。这是一个将网络数据传入CompletionHandler处理的方法。另一个做法是将CompletionHandler做成匿名内部类,buffer做成一个final本地变量从而是它能作用在completion handler的范围内。尽管你可以安全地在多线程(环境)共享AsynchronousSocketChannel和AsynchronousServerSocketChannel,但是同时只有一个线程能对channel读写(不过可以同时有一个线程读一个线程写)。如果线程尝试在另一线程读时读取数据,那么会抛出一个ReadPendingException。同样,线程尝试在另个一线程写时写入数据则会抛出WritePendingException。

Socket Options (Java 7)

Beginning in Java 7, SocketChannel, ServerSocketChannel, AsynchronousServerSocketChannel, AsynchronousSocketChannel, and DatagramChannel all implement the new NetworkChannel interface. The primary purpose of this interface is to support the various TCP options such as TCP_NODELAY, SO_TIMEOUT, SO_LINGER, SO_SNDBUF, SO_RCVBUF, and SO_KEEPALIVE discussed in Chapter 8 and Chapter9. The options have the same meaning in the underlying TCP stack whether set on
a socket or a channel. However, the interface to these options is a little different. Rather than individual methods for each supported option, the channel classes each have just three methods to get, set, and list the supported options:

SocketChannel, ServerSocketChannel, AsynchronousServerSocketChannel, AsynchronousSocketChannel, 和DatagramChannel在java7试想了新NetworkChannel接口。接口的原始目的是支持多个TCP配置选项,诸如第8和9章讨论过的TCP_NODELAY, SO_TIMEOUT, SO_LINGER, SO_SNDBUF, SO_RCVBUF, 和SO_KEEPALIVE。(后面没看懂不翻译)

<T> T getOption(SocketOption<T> name) throws IOException<T> NetworkChannel setOption(SocketOption<T> name, T value) throws IOExceptionSet<SocketOption<?>> supportedOptions()
The SocketOption class is a generic class specifying the name and type of each option. The type parameter <T> determines whether the option is a boolean, Integer, or NetworkInterface. The StandardSocketOptions class provides constants for each of the
11 options Java recognizes:
• SocketOption<NetworkInterface> StandardSocketOptions.IP_MULTICAST_IF• SocketOption<Boolean> StandardSocketOptions.IP_MULTICAST_LOOP• SocketOption<Integer> StandardSocketOptions.IP_MULTICAST_TTL• SocketOption<Integer> StandardSocketOptions.IP_TOS• SocketOption<Boolean> StandardSocketOptions.SO_BROADCAST• SocketOption<Boolean> StandardSocketOptions.SO_KEEPALIVE• SocketOption<Integer> StandardSocketOptions.SO_LINGER• SocketOption<Integer> StandardSocketOptions.SO_RCVBUF• SocketOption<Boolean> StandardSocketOptions.SO_REUSEADDR• SocketOption<Integer> StandardSocketOptions.SO_SNDBUF• SocketOption<Boolean> StandardSocketOptions.TCP_NODELAY
For example, this code fragment opens a client network channel and sets SO_LINGER to 240 seconds:

NetworkChannel channel = SocketChannel.open();channel.setOption(StandardSocketOptions.SO_LINGER, 240);
Different channels and sockets support different options. For instance, ServerSocketChannel supports SO_REUSEADDR and SO_RCVBUF but not SO_SNDBUF. Trying to set an option the channel doesn’t support throws an UnsupportedOperationException.
Example 11-7 is a simple program to list all supported socket options for the differenttypes of network channels.
Example 11-7. Listing supported options
import java.io.*;import java.net.*;import java.nio.channels.*;public class OptionSupport { public static void main(String[] args) throws IOException {  printOptions(SocketChannel.open());  printOptions(ServerSocketChannel.open());  printOptions(AsynchronousSocketChannel.open());  printOptions(AsynchronousServerSocketChannel.open());  printOptions(DatagramChannel.open()); } private static void printOptions(NetworkChannel channel) throws IOException {  System.out.println(channel.getClass().getSimpleName() + " supports:");  for (SocketOption<?> option : channel.supportedOptions()) {   System.out.println(option.name() + ": " + channel.getOption(option));  }  System.out.println();  channel.close(); }}
Here’s the output showing which options are supported by which types of channels, and what the default values are:
SocketChannelImpl supports:
SO_OOBINLINE: false
SO_REUSEADDR: false
SO_LINGER: -1
SO_KEEPALIVE: false
IP_TOS: 0
SO_SNDBUF: 131072
SO_RCVBUF: 131072
TCP_NODELAY: false
ServerSocketChannelImpl supports:
SO_REUSEADDR: true
SO_RCVBUF: 131072
UnixAsynchronousSocketChannelImpl supports:
SO_KEEPALIVE: false
Channels | 387
SO_REUSEADDR: false
SO_SNDBUF: 131072
TCP_NODELAY: false
SO_RCVBUF: 131072
UnixAsynchronousServerSocketChannelImpl supports:
SO_REUSEADDR: true
SO_RCVBUF: 131072
DatagramChannelImpl supports:
IP_MULTICAST_TTL: 1
SO_BROADCAST: false
SO_REUSEADDR: false
IP_MULTICAST_IF: null
IP_TOS: 0
IP_MULTICAST_LOOP: true
SO_SNDBUF: 9216
SO_RCVBUF: 196724

0 0
原创粉丝点击