看透SpringMVC系列(一)Java中的Socket
阿新 • • 發佈:2019-01-06
最近正在看這本書《看透SpringMVC:原始碼分析與實戰》,作者韓路彪。
推薦用微信讀書APP,下面基本照抄上面的,覺得不過癮可以去自己看
Java中的Socket分為兩種:普通socket和NioSocket。
同步阻塞IO(JAVA BIO):
同步並阻塞,伺服器實現模式為一個連線一個執行緒,即客戶端有連線請求時伺服器端就需要啟動一個執行緒進行處理,如果這個連線不做任何事情會造成不必要的執行緒開銷,當然可以通過執行緒池機制改善。
123
456
//服務端 public static void main(String[] args) throws Exception { PrintWriter pw = null; ServerSocket server = null; Socket socket = null; BufferedReader bufferedReader = null; try { server = new ServerSocket(8080); socket = server.accept();//這裡阻塞 InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream()); bufferedReader = new BufferedReader(inputStreamReader); String receivedMsg = bufferedReader.readLine(); System.out.println("從客戶端接收到資料:" + receivedMsg); //接下來服務端回傳資料給客戶端 pw = new PrintWriter(socket.getOutputStream()); pw.println("已經收到資料了"); pw.flush(); } finally { if(pw != null) pw.close(); if(server != null) server.close(); if(socket != null) socket.close(); if(pw != null) pw.close(); if(bufferedReader != null) bufferedReader.close(); } }
//客戶端 public static void main(String[] args) throws Exception { Socket socket = null; BufferedReader bufferedReader = null; PrintWriter pw = null; try { socket= new Socket("127.0.0.1", 8080); InputStreamReader inputStreamReader = new InputStreamReader(socket.getInputStream()); //接下來服務端回傳資料給客戶端 pw = new PrintWriter(socket.getOutputStream()); pw.println("客戶端傳送資料了"); pw.flush(); bufferedReader = new BufferedReader(inputStreamReader); String receivedMsg = bufferedReader.readLine(); System.out.println("從服務端接收到資料:" + receivedMsg); } catch (Exception e) { e.printStackTrace(); } finally { if(pw != null) pw.close(); if(socket != null) socket.close(); if(pw != null) pw.close(); if(bufferedReader != null) bufferedReader.close(); }
同步非阻塞IO(Java NIO) : 同步非阻塞,伺服器實現模式為一個請求一個執行緒,即客戶端傳送的連線請求都會註冊到多路複用器上,多路複用器輪詢到連線有I/O請求時才啟動一個執行緒進行處理。使用者程序也需要時不時的詢問IO操作是否就緒,這就要求使用者程序不停的去詢問。
非同步阻塞IO(Java NIO):
此種方式下是指應用發起一個IO操作以後,不等待核心IO操作的完成,等核心完成IO操作以後會通知應用程式,這其實就是同步和非同步最關鍵的區別,同步必須等待或者主動的去詢問IO是否完成,那麼為什麼說是阻塞的呢?因為此時是通過select系統呼叫來完成的,而select函式本身的實現方式是阻塞的,而採用select函式有個好處就是它可以同時監聽多個檔案控制代碼(如果從UNP的角度看,select屬於同步操作。因為select之後,程序還需要讀寫資料),從而提高系統的併發性!
nio部分後面補上
package nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.concurrent.TimeUnit;
public class NIOClient {//客戶端
public static void main(String[] args) {
ByteBuffer buffer = ByteBuffer.allocate(1024);
SocketChannel socketChannel = null;
try
{
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress("127.0.0.1",8080));
if(socketChannel.finishConnect())
{
int i=0;
while(true)
{
TimeUnit.SECONDS.sleep(1);
String info = "I'm "+i+++"-th information from client";
buffer.clear();
buffer.put(info.getBytes());
buffer.flip();
while(buffer.hasRemaining()){
System.out.println(buffer);
socketChannel.write(buffer);
}
}
}
}
catch (IOException | InterruptedException e)
{
e.printStackTrace();
}
finally{
try{
if(socketChannel!=null){
socketChannel.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
}
package nio;
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.util.Iterator;
public class NIOServer {//服務端
private static final int BUF_SIZE = 1024;
private static final int PORT = 8080;
private static final int TIMEOUT = 3000;
public static void main(String[] args) {
selector();
}
public static void handleAccept(SelectionKey key) throws IOException {
ServerSocketChannel ssChannel = (ServerSocketChannel) key.channel();
SocketChannel sc = ssChannel.accept();
sc.configureBlocking(false);
sc.register(key.selector(), SelectionKey.OP_READ, ByteBuffer.allocateDirect(BUF_SIZE));
}
public static void handleRead(SelectionKey key) throws IOException {
SocketChannel sc = (SocketChannel) key.channel();
ByteBuffer buf = (ByteBuffer) key.attachment();
long bytesRead = sc.read(buf);
while (bytesRead > 0) {
buf.flip();
while (buf.hasRemaining()) {
System.out.print((char) buf.get());
}
System.out.println();
buf.clear();
bytesRead = sc.read(buf);
}
if (bytesRead == -1) {
sc.close();
}
}
public static void handleWrite(SelectionKey key) throws IOException {
ByteBuffer buf = (ByteBuffer) key.attachment();
buf.flip();
SocketChannel sc = (SocketChannel) key.channel();
while (buf.hasRemaining()) {
sc.write(buf);
}
buf.compact();
}
public static void selector() {
Selector selector = null;
ServerSocketChannel ssc = null;
try {
selector = Selector.open();
ssc = ServerSocketChannel.open();
ssc.socket().bind(new InetSocketAddress(PORT));
ssc.configureBlocking(false);
ssc.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
if (selector.select(TIMEOUT) == 0) {
System.out.println("==");
continue;
}
Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
handleAccept(key);
}
if (key.isReadable()) {
handleRead(key);
}
if (key.isWritable() && key.isValid()) {
handleWrite(key);
}
if (key.isConnectable()) {
System.out.println("isConnectable = true");
}
iter.remove();
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (selector != null) {
selector.close();
}
if (ssc != null) {
ssc.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}