package designpattern.nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator;
public class NIOServer {
public static void main(String[] args) throws IOException {
// 建立ServerSocketChannel,監聽8080端口
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress());
// 設定為非阻塞模式
serverSocketChannel.configureBlocking(false);
// 為serverSocketChannel注冊選擇器
Selector selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
// 建立處理器
while (true) {
// 等待請求,每次等待阻塞3s,超過3s後線程繼續向下運作,如果傳入0或者不傳入參數将一直阻塞
if (selector.select() == ) {
System.out.println("等待請求逾時....");
continue;
}
System.out.println("處理請求....");
// 擷取待處理的SelectionKey
Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();
while (keyIter.hasNext()) {
SelectionKey key = keyIter.next();
// 啟動新線程處理SelectionKey
new Thread(new HttpHandler(key)).run();
// 處理完畢,從待處理的SelectionKey疊代器中移除目前所使用的key
keyIter.remove();
}
}
}
}
package designpattern.nio;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import org.apache.commons.lang3.StringUtils;
public class HttpHandler implements Runnable {
private int bufferSize = ;
private String localCharset = "UTF-8";
private SelectionKey key;
public HttpHandler() {
}
public HttpHandler(SelectionKey key) {
this.key = key;
}
public void handlerAccept() throws IOException {
SocketChannel clientChannel = ((ServerSocketChannel) key.channel()).accept();
clientChannel.configureBlocking(false);
clientChannel.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
}
public void handleRead() throws IOException {
// 擷取channel
SocketChannel socketChannel = (SocketChannel) key.channel();
// 擷取buffer并重置
ByteBuffer buffer = (ByteBuffer) key.attachment();
buffer.clear();
// 沒有讀到内容則關閉
if (socketChannel.read(buffer) == -) {
socketChannel.close();
} else {
// 接收請求資料
buffer.flip();
String receivedString = Charset.forName(localCharset).newDecoder().decode(buffer).toString();
// 控制台列印請求封包頭
String[] requestMessage = receivedString.split("\r\n");
for (String s : requestMessage) {
System.out.println(s);
// 遇到空行說明封包頭已經列印完
if (StringUtils.isEmpty(s)) {
break;
}
}
// 控制台列印首行資訊
String[] firstLine = requestMessage[].split(" ");
System.out.println();
System.out.println("Method:\t" + firstLine[]);
System.out.println("url:\t" + firstLine[]);
System.out.println("HTTP Version:\t" + firstLine[]);
System.out.println();
// 傳回用戶端
StringBuilder sendString = new StringBuilder();
sendString.append("HTTP/1.1 200 OK\r\n");// 響應封包首行,200表示處理成功
sendString.append("Content-Type:text/html;charset=" + localCharset + "\r\n");
sendString.append("\r\n");// 封包頭結束後加一個空行
sendString.append("<html><head><title>顯示封包</title></head></body>");
sendString.append("接收到請求封包是:<br/>");
for (String s : requestMessage) {
sendString.append(s + "<br/>");
}
sendString.append("</body></html>");
buffer = ByteBuffer.wrap(sendString.toString().getBytes(localCharset));
socketChannel.write(buffer);
socketChannel.close();
}
}
@Override
public void run() {
try {
// 接收到連接配接請求時
if (key.isAcceptable()) {
handlerAccept();
}
// 讀資料
if (key.isReadable()) {
handleRead();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
自己動手實作HTTP協定