文章目錄
第四章 進階4.1 多任務處理
迭代伺服器:當一個用戶端向一個已經被其他用戶端佔用的伺服器發送串連請求時,雖然其在串連建立後即可向伺服器端發送資料,伺服器端在處理完已有用戶端的請求前,卻不會對新的用戶端作出響應。
並行伺服器:可以單獨處理沒一個串連,且不會產生幹擾。並行伺服器分為兩種:一客戶一線程和線程池。
4.1.1 Java多線程
Java提供了兩種在一個新線程中執行任務的方法:1)為Thread類定義一個帶有run()方法的子類,在run()方法中包含要執行的任務,並執行個體化這個子類;或2)定義一個實現了Runnable介面的類,並在run()方法中包含要執行的任務,再將這個類的一個執行個體傳遞給Thread的建構函式。
4.1.2 伺服器協議
要求:多任務伺服器方法與用戶端--伺服器協議獨立。
下面是一個顯示回顯協議的代碼。
package com.suifeng.tcpip.chapter4;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.Socket;import java.util.logging.Logger;/** * 獨立於客戶服務器的協議 * @author Suifeng * */public class EchoProtocol implements Runnable{private static final int BUFFER_SIZE = 32;private Socket socket;private Logger logger;public EchoProtocol(Socket socket, Logger logger) {super();this.socket = socket;this.logger = logger;}public static void handleEchoClient(Socket socket, Logger logger){try{InputStream in = socket.getInputStream();OutputStream out = socket.getOutputStream();int totalBytes = 0;int recvSize = -1;byte[] buffer = new byte[BUFFER_SIZE];// 迴圈執行知道串連關閉while((recvSize = in.read(buffer)) != -1){// 接收到資料後立即返回out.write(buffer, 0, recvSize);totalBytes += recvSize;}logger.info(Thread.currentThread().getName()+" is handling Echo now");logger.info("Client "+socket.getRemoteSocketAddress()+" echoed "+totalBytes+" bytes");}catch (IOException e){logger.warning("Exception in echo protocol:"+e.getMessage());e.printStackTrace();}finally{try{socket.close();}catch (IOException e){// TODO Auto-generated catch blocke.printStackTrace();}}}@Overridepublic void run(){handleEchoClient(socket, logger);}}
4.1.3 一客戶一線程
在一客戶一線程(thread-per-client)的伺服器中,為沒一個串連建立一個新的線程來處理。伺服器迴圈執行一些任務,在指定的連接埠偵聽,反覆接收用戶端傳入的串連請求,並為每個串連建立新的線程來對其進行處理。
package com.suifeng.tcpip.chapter4;import java.io.IOException;import java.net.ServerSocket;import java.net.Socket;import java.util.logging.Logger;/** * 一客戶一線程伺服器處理 * @author Suifeng * */public class TCPEchoServerThread{public static void main(String[] args) throws IOException{if(args.length != 1){throw new IllegalArgumentException("Parameter:<Port>");}// 日誌記錄器Logger logger = Logger.getLogger("practical");// 伺服器偵聽連接埠int serverPort = Integer.parseInt(args[0]);ServerSocket serverSocket = new ServerSocket(serverPort);logger.info("Server is started!!!!");while(true){Socket socket = serverSocket.accept();// 接收到用戶端的請求後立即建立新的線程進行處理Thread t = new Thread(new EchoProtocol(socket,logger));t.start();logger.info("Created and started Thread "+t.getName());}}}
啟動伺服器端,監聽39393連接埠
啟動用戶端(使用第二章用的的TCP用戶端即可)
查看伺服器端
再次啟動一次用戶端
再次查看伺服器端