簡易非阻塞http服務器

  • 說明

        須要理解阻塞和非阻塞的區別,特別要注意非阻塞和異步不是一個概念,這個很容易弄錯。雲盤裏面netty的書會講這幾個方面的區別,nodejs深刻淺出關於異步編程章節裏面        也會講到網絡通訊底層的知識,能夠看看下面文章:html

        http://blog.csdn.net/hguisu/article/details/7453390java

        http://www.cnblogs.com/dolphin0520/p/3916526.htmlnode


  •  Handler接口類
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 }
View Code

 

  • 請求鏈接Handler實現類
 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 }
View Code

 

  •  請求處理Handler實現類
 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 }
View Code

 


 

  •  nio編寫的服務端類
 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 }
View Code

 

  • html文件

        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的書。服務器

相關文章
相關標籤/搜索