傳統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()); } } }}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()可以喚醒selector。 SelectionKey.OP_WRITE一般很少使用OP_WRITE表示底層緩沖區是否有空間,是則響應返還true。
新聞熱點
疑難解答