須要理解阻塞和非阻塞的區別,特別要注意非阻塞和異步不是一個概念,這個很容易弄錯。雲盤裏面netty的書會講這幾個方面的區別,nodejs深刻淺出關於異步編程章節裏面 也會講到網絡通訊底層的知識,能夠看看下面文章:html
http://blog.csdn.net/hguisu/article/details/7453390java
http://www.cnblogs.com/dolphin0520/p/3916526.htmlnode
1 package study.socket.tcp.nonblock.simpleserver; 2 3 import java.io.IOException; 4 import java.nio.channels.SelectionKey; 5 6 public interface Handler { 7 8 public void handle(SelectionKey selectionKey) throws IOException; 9 }
1 package study.socket.tcp.nonblock.simpleserver; 2 3 import java.io.IOException; 4 import java.nio.channels.SelectionKey; 5 import java.nio.channels.ServerSocketChannel; 6 import java.nio.channels.SocketChannel; 7 8 public class AcceptHandler implements Handler{ 9 10 @Override 11 public void handle(SelectionKey selectionKey) throws IOException { 12 System.out.println("開始處理鏈接請求"); 13 try { 14 Thread.sleep(60000); 15 } catch (InterruptedException e) { 16 e.printStackTrace(); 17 } 18 //獲得事件發生的通道 19 ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel(); 20 //得到和客戶端鏈接的通道 21 SocketChannel socketChannel = ssc.accept(); 22 //設置曾非阻塞模式 23 socketChannel.configureBlocking(false); 24 //在和客戶端鏈接成功以後,爲了能夠接收到客戶端的信息,須要給通道設置讀權限 25 socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ, new RequestHandler()); 26 System.out.println("鏈接成功"); 27 } 28 29 }
1 package study.socket.tcp.nonblock.simpleserver; 2 3 import java.io.FileInputStream; 4 import java.io.IOException; 5 import java.nio.ByteBuffer; 6 import java.nio.CharBuffer; 7 import java.nio.channels.FileChannel; 8 import java.nio.channels.SelectionKey; 9 import java.nio.channels.SocketChannel; 10 import java.nio.charset.Charset; 11 import java.nio.charset.CharsetDecoder; 12 13 public class RequestHandler implements Handler{ 14 15 @Override 16 public void handle(SelectionKey selectionKey) throws IOException { 17 FileInputStream fis = null; 18 SocketChannel socketChannel = null; 19 try { 20 socketChannel = (SocketChannel) selectionKey.channel(); 21 ByteBuffer byteBuffer = ByteBuffer.allocate(1024); 22 socketChannel.read(byteBuffer); 23 byte[] data = byteBuffer.array(); 24 String msg = new String(data); 25 System.out.println("接收客戶端的消息:" + msg); 26 byteBuffer.flip(); 27 String request = decode(byteBuffer); 28 System.out.println("客戶端請求消息:" + request); 29 //生成http響應消息 30 StringBuffer sb = new StringBuffer("HTTP/1.1 200 OK\r\n"); 31 sb.append("Content-Type:text/html\r\n\r\n"); 32 //發送http響應第一行和響應頭 33 socketChannel.write(encode(sb.toString())); 34 35 //獲取http請求的第一行 36 String firstLineOfRequst = request.substring(0, request.indexOf("\r\n")); 37 String filePath = SimpleHttpServer.class.getResource("/").getPath(); 38 System.out.println("路徑:" + filePath); 39 System.out.println("測試"); 40 if(firstLineOfRequst.indexOf("login.html") != -1) { 41 fis = new FileInputStream(filePath + "study/socket/block/httpserver/login.html"); 42 }else { 43 fis = new FileInputStream(filePath + "study/socket/block/httpserver/hello.html"); 44 } 45 FileChannel fc = fis.getChannel(); 46 fc.transferTo(0, fc.size(), socketChannel); 47 } catch(Exception e){ 48 e.printStackTrace(); 49 }finally { 50 if(fis != null) { 51 try { 52 fis.close(); 53 } catch (IOException e1) { 54 e1.printStackTrace(); 55 } 56 } 57 if(socketChannel != null) { 58 try { 59 socketChannel.close(); 60 } catch (IOException e1) { 61 e1.printStackTrace(); 62 } 63 } 64 } 65 } 66 //編碼 67 private String decode(ByteBuffer bb) throws Exception{ 68 Charset charset = Charset.forName("utf-8"); 69 CharsetDecoder decoder = charset.newDecoder(); 70 CharBuffer charBuffer = decoder.decode(bb); 71 System.out.println( " charBuffer= " + charBuffer); 72 System.out.println(charBuffer.toString()); 73 System.out.println("編碼"); 74 return charBuffer.toString(); 75 } 76 //解碼 77 private ByteBuffer encode(String str) { 78 System.out.println("解碼"); 79 return ByteBuffer.wrap(str.getBytes()); 80 } 81 }
1 package study.socket.tcp.nonblock.simpleserver; 2 3 import java.io.IOException; 4 import java.net.InetSocketAddress; 5 import java.nio.channels.SelectionKey; 6 import java.nio.channels.Selector; 7 import java.nio.channels.ServerSocketChannel; 8 import java.util.Iterator; 9 10 /** 11 * 非阻塞式簡易http服務器 12 * @author yj 13 * 14 */ 15 public class SimpleHttpServer { 16 17 private int port = 8080; 18 private Selector selector; 19 20 public void initServer() throws IOException{ 21 //打開服務器套接字通道 22 ServerSocketChannel ssc = ServerSocketChannel.open(); 23 //將服務端套接字通道鏈接方式改成非阻塞模式 24 ssc.configureBlocking(false); 25 //綁定端口 26 ssc.socket().bind(new InetSocketAddress(port)); 27 //打開通道選擇器 28 this.selector = Selector.open(); 29 //將服務器套接字通道的OP_ACCEPT事件註冊到通道選擇器上 30 ssc.register(selector, SelectionKey.OP_ACCEPT, new AcceptHandler()); 31 } 32 33 public void service() throws IOException{ 34 while(true) { 35 int n = selector.select(); 36 System.out.println("開始處理請求"); 37 if(n == 0) continue; 38 //獲取通道選擇器事件 39 Iterator<SelectionKey> itr = this.selector.selectedKeys().iterator(); 40 while(itr.hasNext()) { 41 SelectionKey sk = null; 42 try { 43 sk = itr.next(); 44 itr.remove(); 45 Handler handler = (Handler) sk.attachment(); 46 handler.handle(sk); 47 } catch(Exception e) { 48 e.printStackTrace(); 49 } 50 } 51 System.out.println("請求處理完成"); 52 } 53 } 54 55 public static void main(String[] args) { 56 try { 57 SimpleHttpServer2 nioServer = new SimpleHttpServer2(); 58 nioServer.initServer(); 59 nioServer.service(); 60 } catch (Exception e) { 61 e.printStackTrace(); 62 } 63 } 64 }
html文件使用《簡易阻塞http服務器》中的兩個html文件,注意文件目錄與上面類文件所在目錄一致。編程
啓動main方法,瀏覽器輸入:http://ip:port/或http://ip:port/hello.html訪問hello.html,輸入http://ip:port/login.html訪問login.html.瀏覽器
http://yunpan.cn/cwJGv4vUm9kTf 訪問密碼 a74b 裏面包含了io.socket和nio.socket的一些簡單代碼,還有上面說的netty的書。服務器