java nio socket客户端和服务器端的实现,nio socket是java.nio包下的socket,它比java.net下的socket更加高效,是一种非阻塞式的socket,采用Selector选择器形式来选择空闲的channel通道执行,Selector如我们银行叫号机器,整个项目只有一个selector叫号器,channel通道一旦建立,只要客户端不退出,就一直保持长连接的形式,如图所示。
1:下面来通过案例让我们理解nio socket的使用方法,先来看看socket server服务器端的写法,代码如下。
package com.baidu; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; public class NioSocketServer { private Selector selector; private InetSocketAddress socketAddress; private Map<SocketChannel,List> channelMap; //构造方法 public NioSocketServer(String address,int port){ socketAddress = new InetSocketAddress(address, port); channelMap = new HashMap<SocketChannel,List>(); } public static void main(String[] args) { Runnable server = new Runnable() { @Override public void run() { try { new NioSocketServer("localhost", 8888).startServer(); } catch (IOException e) { e.printStackTrace(); } } }; //启动线程 new Thread(server).start(); } //创建服务器channel通道 protected void startServer() throws IOException { //Selector对象是通过调用静态工厂方法open()来实例化 selector = Selector.open(); ServerSocketChannel serverChannel = ServerSocketChannel.open(); //非阻塞 serverChannel.configureBlocking(false); serverChannel.socket().bind(socketAddress); serverChannel.register(selector, SelectionKey.OP_ACCEPT); System.out.println("服务器启动了........."); //一直处于循环状态,便于处理客户端信息 while(true){ //等待客户端的事件 selector.select(); Iterator<SelectionKey> keys = selector.selectedKeys().iterator(); while(keys.hasNext()){ SelectionKey key = keys.next(); //防止相同的操作 keys.remove(); //无效则不进行下面操作 if (!key.isValid()) { continue; } //如果是客户端连接操作 if (key.isAcceptable()) { acceptConnection(key); } //如果是客户端来的信息,则读出来 if (key.isReadable()) { readMessage(key); } } } } //客户端连接操作 private void acceptConnection(SelectionKey key) throws IOException { ServerSocketChannel serverChannel = (ServerSocketChannel)key.channel(); SocketChannel channel = serverChannel.accept(); channel.configureBlocking(false); Socket socket = channel.socket(); SocketAddress remoteAddress = socket.getRemoteSocketAddress(); System.out.println("连接的客户端ip是:"+remoteAddress); //开启读取数据 channelMap.put(channel, new ArrayList<>()); channel.register(selector, SelectionKey.OP_READ); } //读取客户端信息 private void readMessage(SelectionKey key) throws IOException { SocketChannel channel = (SocketChannel)key.channel(); try { //nio的字节缓存大小 ByteBuffer buffer = ByteBuffer.allocate(1024); int num = -1; num = channel.read(buffer); //如果数据读取完毕 if (num == -1) { channelMap.remove(channel); Socket socket = channel.socket(); SocketAddress remoteAddress = socket.getRemoteSocketAddress(); System.out.println("退出的客户端ip是:"+remoteAddress); channel.close(); key.cancel(); } byte[] datas = new byte[num]; System.arraycopy(buffer.array(), 0, datas, 0, num); String msg = new String(datas); System.out.println("服务端读取到的数据:"+msg); } catch (Exception e) { //客户端异常退出,则关闭通道,不影响服务端socket channelMap.remove(channel); Socket socket = channel.socket(); SocketAddress remoteAddress = socket.getRemoteSocketAddress(); System.out.println("退出的客户端ip是:"+remoteAddress); channel.close(); key.cancel(); } } }
2:nio client客户端代码,启动连接服务器端。
package com.baidu; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SocketChannel; import java.util.Scanner; public class NioSocketClient { public static void main(String[] args) throws IOException { InetSocketAddress socketAddress = new InetSocketAddress("localhost", 8888); SocketChannel client = SocketChannel.open(socketAddress); while(true){ //获取键盘录入 Scanner scanner = new Scanner(System.in); System.out.println("我说:"); String message = scanner.nextLine(); ByteBuffer buffer = ByteBuffer.wrap(message.getBytes()); client.write(buffer); } } }
学会nio socket非常的重要,因为它是netty框架的基础,对于以后了解netty socket非常的有用。