ServerSocket和ServerSocketChannel实例

2/22/2017来源:ASP.NET技巧人气:3028

1.传统Socket

传统Socket单线程只能处理一个连接,要处理多个连接需要借助线程或者线程池,但是这样比较消耗资源。

public class ServerSocketDemo { public static void main(String[] args) throws IOException { new ServerSocketDemo().start(8080); } PRivate void start(int port) throws IOException { ServerSocket serverSocket = new ServerSocket(port,2000); System.out.println("server is start!"); //线程池可以处理多个连接比较消耗性能 ExecutorService executorService= Executors.newCachedThreadPool(); try { while (true) { //accept 会阻塞 Socket socket = serverSocket.accept(); System.out.println("有客户端连接来了"+socket.toString()); executorService.execute(new SocketHandler(socket)); } } catch (Exception ex) { System.out.println(ex.getMessage()); } finally { serverSocket.close(); } } } public class SocketHandler implements Runnable { private Socket socket; public SocketHandler(Socket socket) { this.socket = socket; } public void run() { InputStream in = null; OutputStream out = null; try { in = socket.getInputStream(); out = socket.getOutputStream(); byte[] bytes = new byte[1024]; while (true) { //会阻塞 int n = in.read(bytes); if (n == -1) { break; } System.out.println(new String(bytes, 0, n)); out.write(bytes,0,n); } } catch (Exception ex) { System.out.println(ex.getMessage()); } finally { try { System.out.print("关闭 socket"); socket.close(); } catch (Exception ex) { System.out.println(ex.getMessage()); } try { if(in!=null) { in.close(); } } catch (Exception ex) { System.out.println(ex.getMessage()); } try { if(out!=null) { out.close(); } } catch (Exception ex) { System.out.println(ex.getMessage()); } } } }

2.NIO

java nio 借鉴了linux下select、poll、epoll模型;其性能有很大的提高。

public class ServerSocketChannelDemo { private Selector selector; public void initServer(int port) throws IOException { //创建ServerSocketChannel ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); serverSocketChannel.socket().bind(new InetSocketAddress(port)); this.selector = Selector.open(); serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); } public void listen() throws IOException { System.out.println("server is start!"); while (true) { //这条语句会阻塞 selector.select(); Iterator<SelectionKey> iterator = this.selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); handler(key); } } } public void handler(SelectionKey key) throws IOException { if (key.isAcceptable()) { handlerAccept(key); } else if (key.isReadable()) { handlerReader(key); } } public void handlerAccept(SelectionKey key) throws IOException { ServerSocketChannel sever = (ServerSocketChannel) key.channel(); SocketChannel channel = sever.accept(); channel.configureBlocking(false); System.out.println("有客服端连接来了" + channel.toString()); channel.register(this.selector, SelectionKey.OP_READ); } public void handlerReader(SelectionKey key) throws IOException { SocketChannel socketChannel = (SocketChannel) key.channel(); ByteBuffer buffer = ByteBuffer.allocate(1024); //不会阻塞 int n = socketChannel.read(buffer); System.out.println(n); if (n > 0) { byte[] data = buffer.array(); System.out.println("服务端收到信息:" + new String(data, 0, n)); buffer.flip(); socketChannel.write(buffer); } else { System.out.println("clinet is close"); key.cancel(); } } public static void main(String[] args) throws IOException { ServerSocketChannelDemo sever = new ServerSocketChannelDemo(); sever.initServer(8081); sever.listen(); } }

NIO 的基本知识可以参考: IO 模型 缓冲区 通道 值得说明是: selector.select()是阻塞的,selector.select(1000)是非阻塞的(1000 表示等待时间)、selector.selectNow()也是非阻塞的、selector.wakeup()可以唤醒selectorSelectionKey.OP_WRITE一般很少使用OP_WRITE表示底层缓冲区是否有空间,是则响应返还true。