简易非阻塞http服务器

  • 说明

        需要理解阻塞和非阻塞的区别,特别要注意非阻塞和异步不是一个概念,这个很容易弄错。云盘里面netty的书会讲这几个方面的区别,nodejs深入浅出关于异步编程章节里面        也会讲到网络通信底层的知识,可以看看下面文章:

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

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


  •  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
");
31             sb.append("Content-Type:text/html

");
32             //发送http响应第一行和响应头
33             socketChannel.write(encode(sb.toString()));
34             
35             //获取http请求的第一行
36             String firstLineOfRequst = request.substring(0, request.indexOf("
"));
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的书。

原文地址:https://www.cnblogs.com/yuyuj/p/4524651.html