- 说明
使用java.net包的ServerSocket也是阻塞的,所以下面的实例把ServerSocketChannel换成ServerSocket效果一样。
- 后台代码
1 package study.socket.tcp.block.httpserver; 2 3 import java.io.FileInputStream; 4 import java.io.IOException; 5 import java.net.InetSocketAddress; 6 import java.net.Socket; 7 import java.nio.ByteBuffer; 8 import java.nio.CharBuffer; 9 import java.nio.channels.FileChannel; 10 import java.nio.channels.ServerSocketChannel; 11 import java.nio.channels.SocketChannel; 12 import java.nio.charset.Charset; 13 import java.nio.charset.CharsetDecoder; 14 import java.util.concurrent.ExecutorService; 15 import java.util.concurrent.Executors; 16 17 /** 18 * 阻塞式简易http服务器 19 * @author yj 20 * 21 */ 22 public class SimpleHttpServer { 23 24 private int port = 8080; 25 private ServerSocketChannel serverSocketChannel = null; 26 private ExecutorService executorService; 27 private static final int POOL_MULTIPE = 4; 28 29 public SimpleHttpServer() throws Exception { 30 executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors()*POOL_MULTIPE); 31 serverSocketChannel = ServerSocketChannel.open(); 32 serverSocketChannel.socket().setReuseAddress(true); 33 serverSocketChannel.socket().bind(new InetSocketAddress(port)); 34 System.out.println("服务器启动"); 35 } 36 37 public void service() { 38 while(true) { 39 System.out.println("服务器接收到客户端请求"); 40 SocketChannel socketChannel = null; 41 try { 42 socketChannel = serverSocketChannel.accept(); 43 } catch (IOException e) { 44 e.printStackTrace(); 45 } 46 executorService.execute(new Handler(socketChannel)); 47 System.out.println("服务端处理完客户端请求"); 48 } 49 } 50 51 private class Handler implements Runnable { 52 53 private SocketChannel socketChannel; 54 55 public Handler(SocketChannel socketChannel) { 56 this.socketChannel = socketChannel; 57 } 58 59 @Override 60 public void run() { 61 handler(); 62 } 63 64 private void handler() { 65 FileInputStream fis = null; 66 try{ 67 new Thread().sleep(60000); 68 Socket socket = socketChannel.socket(); 69 System.out.println("接受到客户连接来自:" + socket.getInetAddress() + ":" + socket.getPort()); 70 ByteBuffer bb = ByteBuffer.allocate(1024); 71 socketChannel.read(bb); 72 bb.flip(); 73 String request = decode(bb); 74 System.out.println("客户端请求消息:" + request); 75 //生成http响应消息 76 StringBuffer sb = new StringBuffer("HTTP/1.1 200 OK\r\n"); 77 sb.append("Content-Type:text/html\r\n\r\n"); 78 //发送http响应第一行和响应头 79 socketChannel.write(encode(sb.toString())); 80 81 //获取http请求的第一行 82 String firstLineOfRequst = request.substring(0, request.indexOf("\r\n")); 83 String filePath = SimpleHttpServer.class.getResource("/").getPath(); 84 System.out.println("路径:" + filePath); 85 System.out.println("测试"); 86 if(firstLineOfRequst.indexOf("login.html") != -1) { 87 fis = new FileInputStream(filePath + "study/socket/block/httpserver/login.html"); 88 }else { 89 fis = new FileInputStream(filePath + "study/socket/block/httpserver/hello.html"); 90 } 91 FileChannel fc = fis.getChannel(); 92 fc.transferTo(0, fc.size(), socketChannel); 93 }catch(Exception e){ 94 e.printStackTrace(); 95 }finally { 96 try { 97 if(fis != null) { 98 fis.close(); 99 } 100 if(socketChannel != null) { 101 socketChannel.close(); 102 } 103 } catch (IOException e) { 104 e.printStackTrace(); 105 } 106 } 107 } 108 109 private String decode(ByteBuffer bb) throws Exception{ 110 Charset charset = Charset.forName("utf-8"); 111 CharsetDecoder decoder = charset.newDecoder(); 112 CharBuffer charBuffer = decoder.decode(bb); 113 System.out.println( " charBuffer= " + charBuffer); 114 System.out.println(charBuffer.toString()); 115 System.out.println("编码"); 116 return charBuffer.toString(); 117 } 118 119 private ByteBuffer encode(String str) { 120 System.out.println("解码"); 121 return ByteBuffer.wrap(str.getBytes()); 122 } 123 124 } 125 126 public static void main(String[] args) { 127 try { 128 new SimpleHttpServer().service(); 129 } catch (Exception e) { 130 e.printStackTrace(); 131 } 132 } 133 }
- hello.html文件
html文件放在类的同级目录下,如果放其他目录下,上面后台代码需要改变取html文件路径。
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Insert title here</title> 6 </head> 7 <body> 8 <h1>hello</h1> 9 </body> 10 </html>
- login.html文件
html文件放在类的同级目录下,如果放其他目录下,上面后台代码需要改变取html文件路径。
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Insert title here</title> 6 </head> 7 <body> 8 <h1>login</h1> 9 </body> 10 </html>
- 测试
浏览器中输入:http://ip:port/或http://ip:port/hello.html访问hello.html,输入:http://ip:port/login.html访问login.html