首先请确保已经学习了Java NIO的基础知识,包括Buffer,Channel文件通道和Socket通道,Selector。关于NIO比起I/O的好处,区别等这里就不说了。具体可以参考后面的参考链接等。
这篇博客主要以一个使用NIO传输文件的例子来学习NIO中网络的基本操作
传统的监控socket方式存在的问题
传统的监控多个socket的Java解决方案是为每个socket创建一个线程并使得线程可以在read调用时阻塞,直到数据可用。实际上这种方案有很大的弊端就是当建立很多链接需要创建很多线程,这些线程的创建管理要耗费很大的资源,也许在这个连接上只发送少量的数据,但是CPU切换也要耗费好多资源。于是为了减少系统线程的开销,采用线程池的办法来减少线程创建和回收的成本,但是有一些使用场景仍然是无法解决的,如果建立的都是长连接,事实上它们并不是每时每刻都在传输数据,这时不可能创建那么多的连接。
使用NIO就可以有效的解决这个问题,利用NIO提供的选择器Selector,可以使用一个线程管理多个连接,这实际上是一种I/O复用。
NIO传输文件例子
下面使用NIO做了一个向服务器端上传文件的例子
服务器端代码
public class Server {
private ByteBuffer buffer = ByteBuffer.allocate(1024*1024);
//使用Map保存每个连接,当OP_READ就绪时,根据key找到对应的文件对其进行写入。若将其封装成一个类,作为值保存,可以再上传过程中显示进度等等
Map<SelectionKey, FileChannel> fileMap = new HashMap<SelectionKey, FileChannel>();
public static void main(String[] args) throws IOException{
Server server = new Server();
server.startServer();
}
public void startServer() throws IOException{
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress(8888));
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("服务器已开启...");
while (true) {
int num = selector.select();
if (num == 0) continue;
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if (key.isAcceptable()) {
ServerSocketChannel serverChannel1 = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = serverChannel1.acce