《看透springMvc源代碼分析與實踐》學習筆記
Socket分為ServerSocket和Socket兩個大類
####### ServerSocket用於服務端,可以通過accept方法監聽請求,監聽到請求后返回Socket,Socket用於具體完成數據傳輸,客戶端直接使用Socket發起請求並傳輸數據。
####### 從JDK1.4開始,java增加了新的io模式,nio在底層采用了新的處理方式,極大的提高了IO效率,我們使用的Socket也屬於IO的一種,nia提供了相應的工具,ServerSocketChannel和SocketChannel,分別對應原來的ServerSocket和Socket。
Buffer、Channel和Selector
####### 現在的快遞模式不會一件一件的送,而是將很多件貨一起拿去送,而且在中轉站都有專門的分揀員負責按配送范圍把貨物分給不同的送貨員,這樣效率就提高了很多。這種模式就相當於NioSocket的處理模式,Buffer就是所要送的貨物,Channel就是送貨員,Selector就是中轉站的分揀員。
####### NioSocket使用中首先要創建ServerSocketChannel,然后注冊Selector,接下來就可以用Selector接受請求並處理了。
NIOServer服務端代碼
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;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
public class TestSocket {
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);
//創建處理器
Handler handler = new Handler(1024);
while(true){
//等待請求,每次等待阻塞3s,超過3s后線程繼續向下運行,如果傳入0或者不傳參數,將一直阻塞
if(selector.select(3000)==0){
System.out.println("等待請求超時......");
continue;
}
System.out.println("處理請求......");
//獲取待處理的SelectionKey
Iterator<SelectionKey> keyIter=selector.selectedKeys().iterator();
while(keyIter.hasNext()){
SelectionKey key = keyIter.next();
try {
//接收到連接請求時
if(key.isAcceptable()){
handler.handleAccept(key);
}
//讀數據
if(key.isReadable()){
handler.handleRead(key);
}
} catch (Exception e) {
keyIter.remove();
continue;
}
//處理完后,從待處理的SelectionKey迭代器中移除當前所使用的key
keyIter.remove();
}
}
}
private static class Handler{
private int bufferSize = 1024;
private String localCharset = "UTF-8";
public Handler(){}
public Handler(int bufferSize){
this(bufferSize,null);
}
public Handler(String LocalCharset){
this(-1,LocalCharset);
}
public Handler(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();
//獲取buffer並重置
ByteBuffer buffer = (ByteBuffer)key.attachment();
buffer.clear();
//沒有獨到內容則關閉
if(sc.read(buffer)==-1){
sc.close();
}else{
//將buffer轉換為讀狀態
buffer.flip();
//將buffer中接收到的值按localCharset格式編碼后保存到receicedString
String receivedString = Charset.forName(localCharset).newDecoder()
.decode(buffer).toString();
System.out.println("receiced from client:"+receivedString);
//返回數據給客戶端
String sendString = "received data:"+receivedString;
buffer = ByteBuffer.wrap(sendString.getBytes(localCharset));
sc.write(buffer);
//關閉Socket
sc.close();
}
}
}
}
Client客戶端代碼
package cn.webmvct.controller;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
public static void main(String[] args) {
String msg = "Client Data";
try {
//創建一個Socket,跟本機的8080端口連接
Socket socket = new Socket("127.0.0.1",8080);
//使用Socket創建PrintWriter和BufferedReader進行讀寫數據
PrintWriter pw = new PrintWriter(socket.getOutputStream());
BufferedReader is = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//發送數據
pw.println(msg);
pw.flush();
//接收數據
String line = is.readLine();
System.out.println("received from server:"+line);
//關閉資源
pw.close();
is.close();
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}