基于阻塞模式的简易javaHTTP服务器

来源:互联网 发布:洛天依mmd动作数据 编辑:程序博客网 时间:2024/06/06 01:58
import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.net.InetSocketAddress;import java.net.Socket;import java.nio.ByteBuffer;import java.nio.CharBuffer;import java.nio.channels.FileChannel;import java.nio.channels.ServerSocketChannel;import java.nio.channels.SocketChannel;import java.nio.charset.Charset;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;// 此类实现 IP 套接字地址(IP 地址 + 端口号)。SocketAddresspublic class SimpleHttpServer {private int port = 80;private ServerSocketChannel serverSocketChannel = null;private ExecutorService executorService;private static final int POOL_MULTIPLE = 4;public SimpleHttpServer() throws IOException {executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_MULTIPLE);serverSocketChannel = ServerSocketChannel.open();// 确保socket关闭之后,端口可以立即被另一个程序使用serverSocketChannel.socket().setReuseAddress(true);// 将服务器程序绑定到一个端口serverSocketChannel.socket().bind(new InetSocketAddress(port));System.out.println("服务器已经启动!");}public void service() {while (true) {SocketChannel socketChannel = null;try {socketChannel = serverSocketChannel.accept();executorService.execute(new Handler(socketChannel));} catch (IOException e) {e.printStackTrace();}}}public static void main(String args[]) throws IOException {new SimpleHttpServer().service();}class Handler implements Runnable {private SocketChannel socketChannel;public Handler(SocketChannel socketChannel) {this.socketChannel = socketChannel;}@Overridepublic void run() {handle(socketChannel);}public void handle(SocketChannel socketChannel) {try {Socket socket = socketChannel.socket();System.out.println("接收到用户连接,来自:" + socket.getInetAddress()+ ":" + socket.getPort());ByteBuffer buffer = ByteBuffer.allocate(1024);socketChannel.read(buffer);// 接收HTTP请求,假定其长度不超过1024个字节buffer.flip();// 将极限设置为位置,再把位置设置为0String request = decode(buffer);System.out.println(request);// 打印HTTP请求// 生成HTTP响应结果StringBuffer sb = new StringBuffer("HTTP/1.1 200 OK\r\n");sb.append("Content-Type:text/html\r\n\r\n");socketChannel.write(encode(sb.toString()));// 输出响应头FileInputStream in;// 获得HTTP请求的第一行 解析请求String firstLineOfRequest = request.substring(0,request.indexOf("\r\n"));if (firstLineOfRequest.indexOf("login.htm") != -1) {System.out.println("hehe");in = new FileInputStream(new File("D://root/login.htm"));}LinkedList elsein = new FileInputStream(new File("D://root/hello.htm"));// 通道Channel用来连接缓冲区与数据源或者数据目的地// FileChannel类是Channel的实现类,代表这一个与文件相连的通道。// 该类实现了ByteChannel、ScatteringByteChannel和GatheringByteChannel接口,支持读写// 、分散读和集中写操作,FIleChannel没有公开的构造方法,因此客户程序不能用new来创建它的实例// 不过在FileInputStream和FileOutStream当中提供了getChannel()返回FileChannel的实例FileChannel fileChannel = in.getChannel();// 将字节从此通道的文件传输到给定的可写入字节通道。/* * public abstract long transferTo(long position, long count, * WritableByteChannel target) throws IOException *//* * 将字节从此通道的文件传输到给定的可写入字节通道。 *  * 试图读取从此通道的文件中给定 position 处开始的 count * 个字节,并将其写入目标通道。此方法的调用不一定传输所有请求的字节;是否传输取决于通道的性质和状态。如果此通道的文件从给定的 * position 处开始所包含的字节数小于 count 个字节,或者如果目标通道是非阻塞的并且其输出缓冲区中的自由空间少于 * count 个字节,则所传输的字节数要小于请求的字节数。 *  * 此方法不修改此通道的位置。如果给定的位置大于该文件的当前大小,则不传输任何字节。如果目标通道中有该位置,则从该位置开始写入各字节 * ,然后将该位置增加写入的字节数。 *  * 与从此通道读取并将内容写入目标通道的简单循环语句相比,此方法可能高效得多。很多操作系统可将字节直接从文件系统缓存传输到目标通道 * ,而无需实际复制各字节。 *  * 参数: position - 文件中的位置,从此位置开始传输;必须为非负数 count - * 要传输的最大字节数;必须为非负数 target - 目标通道 返回: 实际已传输的字节数,可能为零 */long num = fileChannel.transferTo(0, fileChannel.size(),socketChannel);System.out.println(num);// fileChannel.close();} catch (Exception e) {e.printStackTrace();} finally {try {if (socketChannel != null)socketChannel.close();} catch (IOException e) {e.printStackTrace();}}}/* * java.nio.Charset类的每个实例代表特定的字符编码类型。 将字节序列转换为字符串的过程称之为解码;decode * 将字符串转换为字节序列的过程称之为编码 ;encode Charset的静态forName(String * encode)方法返回一个Charset对象 代表encode指定的编码类型 */private Charset charset = Charset.forName("GBK");public String decode(ByteBuffer buffer) {// decode(ByteBuffer buffer) 将ByteBuffer构成的字节序列进行解码 生成CharBufferCharBuffer charBuffer = charset.decode(buffer);return charBuffer.toString();}public ByteBuffer encode(String str) { // 编码return charset.encode(str);}}}

通过输入http://localhost:80/login.htm可以访问本地的这个htm文件,

这个编程是基于阻塞模式的,ServerSocketChannel是继承与SelecteableChannel的子类,默认是阻塞式的

0 0
原创粉丝点击