分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 教程案例

使用NIO建立简单的http服务器

发布时间:2023-09-06 01:19责任编辑:彭小芳关键词:http

NIO同BIO的区别在于NIO的所有操作都可以是非阻塞的,这里尝试将之前用BIO实现的htp服务器改造为用NIO实现,在改造过程中碰到不少问题,只能说知易行难

 ?1 import java.io.IOException; ?2 import java.net.InetSocketAddress; ?3 import java.nio.ByteBuffer; ?4 import java.nio.CharBuffer; ?5 import java.nio.channels.SelectionKey; ?6 import java.nio.channels.Selector; ?7 import java.nio.channels.ServerSocketChannel; ?8 import java.nio.channels.SocketChannel; ?9 import java.nio.charset.Charset; 10 import java.util.Iterator; 11 ?12 public class NioServer { 13 ????private String ip; 14 ?15 ????private int port; 16 ?17 ????private Selector selector; 18 ?19 ????public NioServer(String ip, int port) { 20 ????????this.ip = ip; 21 ????????this.port = port; 22 ????} 23 ?24 ????public void startListen() throws IOException { 25 ????????selector = Selector.open(); 26 ????????ServerSocketChannel serverChannel = ServerSocketChannel.open(); 27 ????????serverChannel.configureBlocking(false); 28 ????????serverChannel.register(selector, SelectionKey.OP_ACCEPT); 29 ????????serverChannel.bind(new InetSocketAddress(ip, port)); 30 ?31 ????????while (true) { 32 ????????????//不能使用select方法,该方法会阻塞,如果在阻塞过程中channel状态就绪,会因此处阻塞而无法执行。 33 ????????????//所以,如果调用阻塞方法,下面对channel状态的处理得另起一个常驻线程 34 ????????????int result = selector.selectNow(); 35 ????????????if (result == 0) { 36 ????????????????continue; 37 ????????????} 38 ?39 ????????????Iterator<SelectionKey> it = selector.selectedKeys().iterator(); 40 ????????????while (it.hasNext()) { 41 ????????????????SelectionKey key = it.next(); 42 ????????????????if (key.isAcceptable()) { 43 ????????????????????accept(key); 44 ????????????????} else if (key.isReadable()) { 45 ????????????????????read(key); 46 ????????????????} else if (key.isWritable()) { 47 ????????????????????write(key); 48 ????????????????} else { 49 ????????????????????System.out.println("Unknow selector type"); 50 ????????????????} 51 ?????????????????52 ????????????????//一定要调用remove方法将已经处理过的SelectionKey清除掉,否则会造成后面的请求无法接受 53 ????????????????it.remove(); 54 ????????????} 55 ????????} 56 ????} 57 ?????58 ????private void accept(SelectionKey key) throws IOException { 59 ????????System.out.println("Receive connection"); 60 ????????ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); 61 ????????SocketChannel channel = serverSocketChannel.accept(); 62 ?????????63 ????????if (channel != null) { 64 ????????????channel.configureBlocking(false); 65 ????????????channel.register(selector, SelectionKey.OP_READ); 66 ????????} 67 ????????System.out.println("Connection end"); 68 ????} 69 ?????70 ????private void read(SelectionKey key) throws IOException { 71 ????????System.out.println("Start read"); 72 ????????SocketChannel channel = (SocketChannel) key.channel(); 73 ????????ByteBuffer buffer = ByteBuffer.allocate(64); 74 ????????boolean hasContent = false; 75 ?????????76 ????????//这里的判断条件不能是不等于-1,因为channel一直都在,只是在数据被读完后里面为空,返回的长度是0.用-1判断会无限循环无法退出 77 ????????while (channel.read(buffer) > 0) { 78 ????????????buffer.flip(); //切换为读模式 79 ????????????CharBuffer cb = Charset.forName("UTF-8").decode(buffer); 80 ????????????System.out.print(cb.toString()); 81 ????????????buffer.clear(); 82 ????????????hasContent = true; 83 ????????} 84 ?????????85 ????????if (hasContent) { 86 ????????????//设置interestOps,用于写响应 87 ????????????key.interestOps(SelectionKey.OP_WRITE); 88 ????????} else { 89 ????????????channel.close(); 90 ????????} 91 ????????System.out.println("Read end"); 92 ????} 93 ?????94 ????private void write(SelectionKey key) throws IOException { 95 ????????System.out.println("Start write"); 96 ????????SocketChannel channel = (SocketChannel) key.channel(); 97 ?????????98 ????????String resText = getResponseText(); 99 ????????ByteBuffer buffer = ByteBuffer.wrap(resText.getBytes());100 ????????101 ????????//此处不可使用channel.write(buffer) != -1来判断,因为在两端都不关闭的情况下,会一直返回0,导致该循环无法退出102 ????????while (buffer.hasRemaining()) {103 ????????????channel.write(buffer);104 ????????}105 ????????channel.close();106 ????????System.out.println("End write");107 ????}108 ????109 ????private String getResponseText() {110 ????????StringBuffer sb = new StringBuffer();111 ????????sb.append("HTTP/1.1 200 OK\n");112 ????????sb.append("Content-Type: text/html; charset=UTF-8\n");113 ????????sb.append("\n");114 ????????sb.append("<html>");115 ????????sb.append(" ?<head>");116 ????????sb.append(" ???<title>");117 ????????sb.append(" ?????NIO Http Server");118 ????????sb.append(" ???</title>");119 ????????sb.append(" ?</head>");120 ????????sb.append(" ?<body>");121 ????????sb.append(" ???<h1>Hello World!</h1>");122 ????????sb.append(" ?</body>");123 ????????sb.append("</html>");124 ????????125 ????????return sb.toString();126 ????}127 ????128 ????public static void main(String[] args) {129 ????????NioServer server = new NioServer("127.0.0.1", 8080);130 ????????try {131 ????????????server.startListen();132 ????????} catch (IOException e) {133 ????????????e.printStackTrace();134 ????????}135 ????}136 137 }

这里是将对请求的接受(accept)也使用Selector处理了,在该场景下,在处理完SelectioKey后一定要remove,否则会导致后面的请求不响应。在jetty源码及其它示例中,Selector只处理了对请求的读以及响应的写,请求接受并没有使用selector,这种场景下可以不remove(仅不出现后续请求不响应的问题,不代表没有其它问题):

 1 ????????while (true) { 2 ????????????SocketChannel channel = serverChannel.accept(); 3 ????????????if(channel != null) { 4 ????????????????channel.configureBlocking(false); 5 ????????????????channel.register(selector, SelectionKey.OP_READ); 6 ????????????} 7 ?????????????8 ????????????//不能使用select方法,该方法会阻塞,如果在阻塞过程中channel状态就绪,会因此处阻塞而无法执行。 9 ????????????//所以,如果调用阻塞方法,下面对channel状态的处理得另起一个常驻线程10 ????????????int result = selector.selectNow();11 ????????????if (result == 0) {12 ????????????????continue;13 ????????????}14 15 ????????????Iterator<SelectionKey> it = selector.selectedKeys().iterator();16 ????????????while (it.hasNext()) {17 ????????????????SelectionKey key = it.next();18 ????????????????if (key.isReadable()) {19 ????????????????????//读取请求中的数据20 ????????????????????read(key);21 ????????????????} else if (key.isWritable()) {22 ????????????????????//写响应数据23 ????????????????????write(key);24 ????????????????} else {25 ????????????????????System.out.println("Unknow selector type: " + key.readyOps());26 ????????????????}27 ????????????}28 ????????}

使用NIO建立简单的http服务器

原文地址:http://www.cnblogs.com/smart-elf/p/7710870.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved