自己动手实现HTTP协议
2017-06-12 13:14
411 查看
Java中的网络通信是通过Socket实现的,我们可以编写自己的SocketServer服务器接收并处理来自客户端Socket的请求。当客户端请求不是很多的时候,ServerSocket完全可以应付,但是当请求增多的时候,这种ServerSocket的模式就不那么合适了。
从JDK1.4开始,Java增加了新的io模式–nio,它在底层采用了新的处理方式,极大地提高了IO的效率。那么我们可以使用NioSocket来完成服务端,以提高处理效率。
那么,接下来我们在NioSocketServer的基础上,自己做一个简单的实现了HTTP协议的例子。
启动这个程序,然后再浏览器输入http://127.0.0.1:8080发起请求,这是控制台和浏览器窗口都会输出这次请求的请求头以及相应的响应信息。
从JDK1.4开始,Java增加了新的io模式–nio,它在底层采用了新的处理方式,极大地提高了IO的效率。那么我们可以使用NioSocket来完成服务端,以提高处理效率。
那么,接下来我们在NioSocketServer的基础上,自己做一个简单的实现了HTTP协议的例子。
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.Iterator; /** * 采用新IO方式的ServerSocket */ public class NIOServer { public static void main(String[] args) throws IOException { //创建ServerSocketChannel,监听8080端口 ServerSocketChannel ssc = ServerSocketChannel.open(); ssc.socket().bind(new InetSocketAddress(8080)); //设置为非阻塞模式 ssc.configureBlocking(false); //给ssc注册选择器 Selector selector = Selector.open(); ssc.register(selector, SelectionKey.OP_ACCEPT); //创建处理器 while (true) { //等待请求,每次等待阻塞3s,超过3s后线程继续向下运行,传入0或不传参数将一直阻塞 if (selector.select(3000) == 0) { System.out.println("等待请求超时……"); continue; } System.out.println("开始处理请求……"); Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); //启动新线程处理SelectionKey new Thread(new HttpHandler(key)).run(); //处理完成后,从待处理的SelectionKey迭代器中移除当前所使用的Key keyIterator.remove(); } } } /** * 内部类HttpHandler,负责处理监听到的请求 */ private static class HttpHandler implements Runnable { private int bufferSize = 1024; private String localCharset = "utf-8"; private SelectionKey key; private HttpHandler(SelectionKey key) { this.key = key; } private HttpHandler(int bufferSize) { this(bufferSize, null); } private HttpHandler(String localCharset) { this(-1, localCharset); } private HttpHandler(int bufferSize, String localCharset) { if (bufferSize > 0) { this.bufferSize = bufferSize; } if (localCharset != null) { this.localCharset = localCharset; } } public void handleAccept(SelectionKey key) throws IOException { SocketChannel sc = ((ServerSocketChannel) key.channel()).accept(); sc.configureBlocking(false); sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize)); } public void handleRead(SelectionKey key) throws IOException { //获取channel SocketChannel sc = (SocketChannel) key.channel(); //获取ByteBuffer并重置 ByteBuffer buffer = (ByteBuffer) key.attachment(); buffer.clear(); //没有读取到内容,关闭信道 if (sc.read(buffer) == -1) { sc.close(); } else { //将buffer转换为读状态 buffer.flip(); //将buffer中的值按localCharset格式编码后保存到receivedString String receivedString = Charset.forName(localCharset).newDecoder().decode(buffer).toString(); //控制台打印请求报文头 String[] requestMessage = receivedString.split("\r\n"); for (String s : requestMessage) { //遇到空行说明报文头已经打印完 if (s.isEmpty()) { break; } System.out.println(s); } //控制台打印首行信息 String[] firstLine = requestMessage[0].split(" "); System.out.println(); System.out.println("Method:\t" + firstLine[0]); System.out.println("URL:\t" + firstLine[1]); System.out.println("HTTP Version:\t" + firstLine[2]); System.out.println(); //返回数据给客户端 StringBuilder sb = new StringBuilder(); sb.append("HTTP/1.1 200 OK\r\n");//响应报文首行,表示请求成功 sb.append("Content-Type:text/html;charset=").append(localCharset).append("\r\n"); sb.append("\r\n");//报文头结束后需要加一个空行 sb.append("<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><title>显示报文</title></head><body>") .append("接收到的报文是:<br/>"); for (String s : requestMessage) { sb.append(s).append("<br/>"); } sb.append("</body></html>"); buffer = ByteBuffer.wrap(sb.toString().getBytes(localCharset)); sc.write(buffer); //关闭socket sc.close(); } } @Override public void run() { try { //接收到连接请求时 if (key.isAcceptable()) { handleAccept(key); } //读数据 if (key.isReadable()) { handleRead(key); } } catch (IOException e) { e.printStackTrace(); } } } }
启动这个程序,然后再浏览器输入http://127.0.0.1:8080发起请求,这是控制台和浏览器窗口都会输出这次请求的请求头以及相应的响应信息。
相关文章推荐
- 自己动手实现HTTP协议
- 利用socket自己实现基于HTTP协议的Web客户端
- 自己动手利用Socket 实现HTTP与HTTPS
- 利用socket自己实现基于HTTP协议的Web服务器
- 看透SpringMVC系列(二)用NIO自己手动实现HTTP协议
- C语言动手实现一个自己的HttP服务
- C#实现http协议GET、POST请求
- [实践篇]+[转]用C#实现HTTP协议下的多线程文件传输
- 用C#实现HTTP协议下的多线程文件传输
- HTTP协议的C语言编程实现实例
- Linux网络编程一步一步学-自己编写一个HTTP协议的目录浏览和文件下载服务器
- C#实现HTTP协议下的多线程文件传输
- 用C#实现HTTP协议下的多线程文件传输
- 用C#实现HTTP协议下的多线程文件传输--转载
- [导入]自己编写QQ挂机软件--基于HTTP的QQ协议之我所见
- HTTP协议的C语言编程实现实例
- 用C#实现HTTP协议下的多线程文件传输
- HTTP协议的C语言编程实现实例
- 用udp实现HTTP Streaming协议从指定的url拉流
- C#实现HTTP协议下的多线程文件传输