Java NIO学习8(Selector 补充版ServerSocketChannel)

大部分是javanio书上的内容 我来整理一番,外加一些解释,着色!

ServerSocketChannel

让我们从最简单的ServerSocketChannel来开始对socket通道类的讨论

ServerSocketChannel是一个基于通道的socket监听器。它同我们所熟悉的java.net.ServerSocket执行相同的基本任务,不过它增加了通道语义,因此能够在非阻塞模式下运行。

用静态的open( )工厂方法创建一个新的ServerSocketChannel对象,将会返回同一个未绑定的java.net.ServerSocket关联的通道。该对等ServerSocket可以通过在返回的ServerSocketChannel上调用socket( )方法来获取。作为ServerSocketChannel的对等体被创建的ServerSocket对象依赖通道实现。这些socket关联的SocketImpl能识别通道。通道不能被封装在随意的socket对象外面。

由于ServerSocketChannel没有bind( )方法,因此有必要取出对等的socket并使用它来绑定到一个端口以开始监听连接。我们也是使用对等ServerSocket的API来根据需要设置其他的socket选项

	ServerSocketChannel ssc = ServerSocketChannel.open();
		ServerSocket serverSocket = ssc.socket(); // Listen on port 1234
		serverSocket.bind(new InetSocketAddress(1234));

同它的对等体java.net.ServerSocket一样,ServerSocketChannel也有accept( )方法。

一旦您创建了一个ServerSocketChannel并用对等socket绑定了它,然后您就可以在其中一个上调用accept( )。

如果您选择在ServerSocket上调用accept( )方法,那么它会同任何其他的ServerSocket表现一样的行为:总是阻塞并返回一个java.net.Socket对象(阻塞的!!!!)

。如果您选择在ServerSocketChannel上调用accept( )方法则会返回SocketChannel类型的对象,返回的对象能够在非阻塞模式下运行。假设系统已经有一个安全管理器(security manager),两种形式的方法调用都执行相同的安全检查。


如果以非阻塞模式被调用,当没有传入连接在等待时,ServerSocketChannel.accept( )会立即返回null (因为他是非阻塞的所以要有返回,)

正是这种检查连接而不阻塞的能力实现了可伸缩性并降低了复杂性。可选择性也因此得到实现。我们可以使用一个选择器实例来注册一个ServerSocketChannel对象以实现新连接到达时自动通知的功能。

演示如何使用一个非阻塞的accept( )方法:

package com.anders.selector2;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ServerSocketChannelApp {
	private static final String MSG = "hello, I must be going \n";

	public static void main(String[] args) throws Exception {

		int port = 8989;
		ServerSocketChannel ssc = ServerSocketChannel.open();
		ServerSocket ss = ssc.socket();
		ss.bind(new InetSocketAddress(port));
		// set no blocking
		ssc.configureBlocking(false);

		ByteBuffer buffer = ByteBuffer.wrap(MSG.getBytes());

		while (true) {
			System.out.println("wait for connection ……");
			SocketChannel sc = ssc.accept();
			
			if (sc == null) {
				// no connections, snooze a while ...
				Thread.sleep(1000);
			} else {
				System.out.println("Incoming connection from " + sc.socket().getRemoteSocketAddress());
				buffer.rewind();
				//write msg to client
				sc.write(buffer);
				sc.close();
			}
		}
	}
}

ps  阻塞和非阻塞

传统的serversocket阻塞模式

public class ServerSocketApp {
	public static void main(String[] args) throws Exception {
		ServerSocket ss = new ServerSocket(8989);
		ss.accept();
		
		System.out.println(1);
	}
}	


运行这个程序 为什么没有输出1 ??? 

 因为ServerSocket  是阻塞模式的 ,什么是阻塞,就是在没有任何连接之前,accept方法一直在那里阻塞着,直到有connection来继续往下执行,所以在运行程序的时候,并没输出1,若要输出  telnet一下就可以了

nio中的 非阻塞:

public static void main(String[] args) throws Exception {

		ServerSocketChannel ssc = ServerSocketChannel.open();
		ServerSocket ss = ssc.socket();
		ss.bind(new InetSocketAddress(8989));
		// set no blocking
		ssc.configureBlocking(false);

		ssc.accept();
		
		System.out.println(1);
		
	}

运行这个程序  有1  输出!!

这就是因为  它是非阻塞模式的。


ServerSocketChannel就说道这里,尤其是阻塞和非阻塞!!!

下篇继续!



  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java NIO 中的 Selector 可以用于多路复用 I/O,它可以同时监控多个 Channel 的 IO 状态,如读写就绪等,从而让你的程序可以同时处理多个网络连接。 使用 Selector 的基本流程如下: 1. 创建 Selector 对象:使用 `Selector.open()` 方法。 2. 创建并配置 Channel:每个 Channel 都必须注册到 Selector 上。 3. 向 Selector 注册感兴趣的事件:使用 `SelectionKey` 对象将 Channel 和感兴趣的事件绑定。 4. 通过 `select()` 方法监控 Channel:该方法会阻塞,直到至少有一个 Channel 处于就绪状态。 5. 处理就绪的 Channel:通过 `selectedKeys()` 方法获取所有就绪的 Channel,然后遍历每一个 Key,并根据 Key 的事件状态进行相应的处理。 6. 关闭 Selector:使用 `close()` 方法关闭 Selector。 以上就是 Selector 的基本使用方法。希望这些信息能帮助你理解和使用 Java NIO 中的 Selector。 ### 回答2: Java NIO(New Input/Output)提供了一种非阻塞I/O的能力,其中的selector是一种重要的组件。它允许程序通过一个单线程来监听多个通道上的事件并做出相应的处理。 使用Selector主要包括以下步骤: 1. 创建Selector实例: Selector selector = Selector.open(); 2. 创建Channel并设置为非阻塞模式: 在使用Selector之前,需要确保Channel处于非阻塞模式,例如SocketChannelServerSocketChannel: SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); 3. 将Channel注册到Selector上: 通过SelectionKey来表示Channel的注册状态,包括感兴趣的操作集合及其附加的数据。可以使用以下方法将Channel注册到Selector上: SelectionKey key = socketChannel.register(selector, SelectionKey.OP_READ); 4. 进行事件监听: 使用Selector的select()方法进行事件监听,它会阻塞,直到有一个或多个事件发生: int readyChannels = selector.select(); if (readyChannels == 0) { continue; } 5. 获取已就绪的事件集合: 通过调用selector.selectedKeys()方法获取已经就绪的事件集合: Set<SelectionKey> selectedKeys = selector.selectedKeys(); 6. 遍历已就绪的事件集合并处理: 遍历selectedKeys集合,处理每一个就绪的事件: Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isReadable()) { // 可读事件处理逻辑 } if (key.isWritable()) { // 可写事件处理逻辑 } keyIterator.remove(); // 处理完毕后需要手动移除该事件,避免重复处理 } 7. 关闭Selector: 使用完Selector后需要及时关闭: selector.close(); 使用Selector可以实现多个通道的事件监听和处理,极大地提高了应用程序的性能和资源利用率。需要注意的是,在使用Selector时,一个线程可以管理多个Channel,但要谨慎处理每个Channel上的事件,以避免阻塞整个Selector处理线程。 ### 回答3: Java NIO(New I/O)是一种非阻塞I/O操作的Java API。它提供了一组用于高效处理I/O操作的类和接口。其中,SelectorNIO的核心组件之一,用于实现非阻塞I/O。 Selector是一个类似于调度员的对象,它可以同时监视多个通道的I/O事件。使用Selector可以实现单线程同时管理多个通道的I/O操作,提高了系统的效率。 使用Selector的主要步骤如下: 1. 创建一个Selector对象:通过调用Selector.open()方法创建一个Selector对象。 2. 将通道注册到Selector上:将需要监视的通道注册到Selector上,例如SocketChannelServerSocketChannel等。通过调用通道的register()方法完成注册。 3. 设置通道的非阻塞模式:通过调用通道的configureBlocking(false)方法将通道设置为非阻塞模式。 4. 选择通道:通过调用Selector的select()方法选择通道,并返回已准备就绪的通道的数量。 5. 处理选择的通道:通过调用Selector的selectedKeys()方法获取选择的通道集合,可以通过遍历通道集合进行相应的读写操作。 6. 取消选择的通道:通过调用SelectionKey的cancel()方法取消选择的通道的注册。 示例代码如下: ```java Selector selector = Selector.open(); SocketChannel socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); socketChannel.connect(new InetSocketAddress("example.com", 80)); socketChannel.register(selector, SelectionKey.OP_CONNECT); while (true) { int readyChannels = selector.select(); if (readyChannels == 0) { continue; } Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isConnectable()) { // 处理连接就绪的通道 SocketChannel channel = (SocketChannel) key.channel(); if (channel.isConnectionPending()) { channel.finishConnect(); } channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 处理读就绪的通道 SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); channel.read(buffer); buffer.flip(); // 处理读取到的数据 } keyIterator.remove(); } } ``` 以上是一个简单的Selector的使用示例,通过这些步骤,可以实现对多个通道的非阻塞I/O操作的监视和处理。需要注意的是,Selector是基于事件驱动的,可以实现高效的I/O操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值