描述:
(1)jdk自帶線程池見 JDK自帶線程池配置
(2)此上傳文件服務器中上傳文件的后綴名通過第一段緩沖字符流傳遞,此緩沖字符流大小為1024,在文件接收端以1024接收、處理。
1、服務器代碼如下(使用jdk自帶線程池):
1 /** 2 * 服務器處理多線程問題 3 * 4 * 1.因為服務器是要很多人訪問的,因此里面一定要用多線程來處理,不然只能一個人一個人的訪問,那還叫Y啥服務器 5 * 6 * 2,拿上面這個文件上傳的例子來說,它將每個連接它的用戶封裝到線程里面去,把用戶要執行的操作定義到 run 方法里面 7 * 一個用戶拿一個線程,拿到線程的就自己去執行,如果有其它用戶來的時候,再給新來的用戶分配一個新的線程 這樣就完成了服務器處理多線程的問題 3. 8 * 在服務器與客戶端互傳數據時,我們要特別注意的是,防止兩個程序造成 死等的狀態,一般原因有以下: 9 * 10 * 1. 客戶端向數據端發送數據時,當發送的是字符時,第次以一行來發送,而服務端在讀取的時候,也是以 一行來讀取,readLine() 11 * 而發送的時候往往只是發送換行以行的內容,而不能發換行也發送過去, 那么服務端在讀取的時候就不讀取不到換行 ,那么 readLine() 就不會停止 2. 12 * 客戶端發送數據時,如果處理的是用 字符流 或是緩沖流的話,一定要記得刷新流,不然的話,數據就會發不出來 3 在用IO 讀取文件里面的數據然后發送到服務端 13 * 時,當家讀取文件 while(in.read()) 讀取文件結束時,而在 服務端的接收程序 14 * while(sin.read())不會接到一個發送完畢的提示,所以會一直等待下去,所以我們在處理這 15 * 個問題的時候,還要將其發送一個文件讀取結束的標志,告訴接收端文件已經讀取完結,不要再等待了 而socket 里面給我們封裝了 shutdownInput 16 * shutdownOutput 兩個操作,此可以關閉 流,兩樣也可以起到告訴 接收方文件傳送完畢的效果 17 * 18 * 19 * 20 * */ 21 public class Server { 22 23 private static Logger logger = LoggerFactory.getLogger(Server.class); 24 private static final Integer PORT = 2222; 25 26 27 public static void main(String args[]) throws Exception { 28 29 ServerSocket server = new ServerSocket(PORT); 30 31 logger.info("服務器啟動:::端口號為:{}",PORT); 32 ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 300, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(3), 33 new ThreadPoolExecutor.CallerRunsPolicy()); 34 35 while (true) { 36 37 Socket client = server.accept(); 38 executor.execute(new UploadThread(client)); 39 // new Thread(new UploadThread(client)).start(); 40 } 41 42 } 43 }
2、上傳文件代碼如下:
package cn.iautos.manager.test.load; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.PrintStream; import java.net.Socket; import java.util.Timer; import java.util.TimerTask; public class Upload { public static void main(String args[]) throws Exception { Timer timer = new Timer(); timer.schedule(new TimerTask() { public void run() { try { System.out.println("--------開始上傳文件-------"); loadMethod(); } catch (Exception e) { e.printStackTrace(); } } }, 0, 500); } public static void loadMethod() throws Exception{ String name = "E:\\qqq.jpg"; Socket client = new Socket("127.0.0.1", 2222); File file = new File(name); String imgSuffix = ImgUtils.getImgSuffix(name); BufferedInputStream fin = new BufferedInputStream(new FileInputStream( file)); // 文件讀取流 PrintStream sout = new PrintStream(client.getOutputStream(), true); // 得到socket流 /** * 添加后綴名 */ byte[] b = new byte[1024]; byte[] bb = (imgSuffix+"\n").getBytes(); for(int j = 0;j<bb.length;j++){ b[j] = bb[j]; } sout.write(b,0,b.length); int len = 0; while ((len = fin.read(b)) != -1) { sout.write(b, 0, len); System.out.println(len + "...發送中"); } client.shutdownOutput(); BufferedInputStream sin = new BufferedInputStream(client .getInputStream()); len = sin.read(b); System.out.println(len); System.out.println(new String(b, 0, len)); sin.close(); sout.close(); fin.close(); } }
3、接收文件代碼如下:
package cn.iautos.manager.test.load; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; import java.net.Socket; public class UploadThread implements Runnable // 將上傳封裝到線程里 { private Socket client; public UploadThread(Socket s) { this.client = s; } public void run() { // String ip = client.getInetAddress().getHostAddress(); // 得到 IP地址 try { BufferedInputStream sin = new BufferedInputStream(client.getInputStream()); // Socket 讀取流 byte b[] = new byte[1024]; int l = sin.read(b); String line = new String(b, 0, l).split("\n")[0]; System.out.println("--------文件后綴為------"+line); File file = new File("E:\\loadServer\\" + ImgUtils.getImgName() + line); BufferedOutputStream fout = new BufferedOutputStream( new FileOutputStream(file)); // 文件輸出流 int len = 0; // 開始從網絡中讀取數據 while (true) { len = sin.read(b); if(len != -1){ fout.write(b, 0, len); }else{ break; } // System.out.println("--------------"+new String(buf,0,len)); } PrintStream sout = new PrintStream(client.getOutputStream()); sout.write("發送成功".getBytes()); // sout.flush(); //雖然是字節流,但其用的是BufferedOutputStream fout.close(); sin.close(); sout.close(); } catch (Exception ex) { System.out.println(); ex.printStackTrace(); } } }