最近在面試,雖然學習了一些新的框架,但是可能問類似於客戶端服務器模型,然后根據其設計,所以就根據面試內容梳理一下客戶端服務器模型。
客戶端基本思路:
1.創建Socket實例,設置端口和IP地址等
2.通過Socket實例,獲取到流對象
3.通過流對象,向其中輸入數據 ,並且在完成后實現關閉流。
(注意事情:1.需要進行異常處理 2.注意關閉流和Socket 3.低級流和高級流的關閉順序)
//客戶端程序
package ServerSocket;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class ClientDome {
public static void main(String[] args) {
Socket socket =null;
OutputStream outputStream=null;
BufferedOutputStream bufferedOutputStream=null;
try {
socket=new Socket("localhost", 6060);
outputStream=socket.getOutputStream();
bufferedOutputStream =new BufferedOutputStream(outputStream);
String str ="Client Dome ..... Are you ok";
bufferedOutputStream.write(str.getBytes());
bufferedOutputStream.flush();
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
bufferedOutputStream.close();
outputStream.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
服務器模型構建:
1.創建一個ServerSocket對象,進行端口監聽。
2.while(true)重復監聽
3.通過端口監聽對象 獲取Socket實例 並且獲取到網絡流
4.輸出網絡流數據 並且關閉流
(注意事情:端口監聽一次 獲取監聽對象多次 低級流和高級流的關閉順序)
//首先這是單線程版本
package ServerSocket;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerSocketDome {
@SuppressWarnings("null")
public static void main(String[] args) {
// 1.建立監聽
ServerSocket serverSocket = null;
InputStream inputStream = null;
BufferedInputStream bufferedInputStream = null;
@SuppressWarnings("unused")
Socket socket = null;
try {
serverSocket =new ServerSocket(6060);
while(true){
socket = serverSocket.accept();
inputStream = socket.getInputStream();
bufferedInputStream = new BufferedInputStream(inputStream);
byte[] bytes=new byte[10];
int len=0;
while((len=bufferedInputStream.read(bytes))!=-1){
System.out.print(new String(bytes, 0, len));
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(bufferedInputStream!=null){
bufferedInputStream.close();
inputStream.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
多線程版本怎么操作,這里即將引入多線程
服務器版本多線程主要是對於請求分線程操作 ,一次連接會單獨分配線程
package ServerSocket;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
//為了應對面試需要 嘗試根據自己思路寫一個新的多線程版本試試
//其實多線程版本是根據單線程改進而來
//具體而言 多線程的服務器 是應對多條請求 不同線程進行處理
public class ServerSocketThreadDome {
public static void main(String[] args) {
//當然 主線程的端口監聽是不能修改的
ServerSocket serverSocket = null;
//標准web服務器的端口是8080
int port=6060;
try {
serverSocket=new ServerSocket(port);
Socket socket=null;
while(true){
socket=serverSocket.accept();
new Thread(new Server(socket)).start();
}
} catch (IOException e) {
e.printStackTrace();
}finally{
if(serverSocket!=null){
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
//這里的多線程說白了 就是為了應對多條請求而處理的結果
//也就是客戶端對象
class Server implements Runnable{
private Socket socket;
public Server(Socket socket) {
super();
this.socket = socket;
}
@Override
public void run() {
InputStream inputStream=null;
BufferedInputStream bufferedInputStream =null;
try {
inputStream = socket.getInputStream();
bufferedInputStream=new BufferedInputStream(inputStream);
byte[] bytes=new byte[1024];
int len=0;
while((len=bufferedInputStream.read(bytes))!=-1){
System.out.print(new String(bytes, 0, len));
System.out.println("當前線程:"+Thread.currentThread().getName());
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
if(bufferedInputStream!=null){
bufferedInputStream.close();
inputStream.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
那么我們引入線程池的概念 有時候面試可能會問線程池
package ServerSocket; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; //首先大話一下線程池,線程池類似於中介結果,我需要的時候找中介借一些人過來 //不需要的時候中介自己回去 我不需要提供其他待遇等等 //就是傳說中的國企或者大型企業的外包部門 public class ServerSocketPoolDome { public static void main(String[] args) { ServerSocket serverSocket = null; //標准web服務器的端口是8080 int port=6060; try { serverSocket=new ServerSocket(port); Socket socket=null; ExecutorService executorService =Executors.newCachedThreadPool(); while(true){ socket=serverSocket.accept(); executorService.execute(new ServerPool(socket)); } } catch (IOException e) { e.printStackTrace(); }finally{ if(serverSocket!=null){ try { serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } } } } } //這里的多線程說白了 就是為了應對多條請求而處理的結果 //也就是客戶端對象 class ServerPool implements Runnable{ private Socket socket; public ServerPool(Socket socket){ super(); this.socket = socket; } @Override public void run() { InputStream inputStream=null; BufferedInputStream bufferedInputStream =null; try { inputStream = socket.getInputStream(); bufferedInputStream=new BufferedInputStream(inputStream); byte[] bytes=new byte[1024]; int len=0; while((len=bufferedInputStream.read(bytes))!=-1){ System.out.print(new String(bytes, 0, len)); System.out.println("當前線程:"+Thread.currentThread().getName()); } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { if(bufferedInputStream!=null){ bufferedInputStream.close(); inputStream.close(); socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
線程池的使用很爽,接下來看看線程池的源碼
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
//線程池創建一個緩沖的線程池
//也就設置線程數目 和 活動時間 以及具體執行的方式
