-----------------
Java培訓
Android培訓 期待與您的交流----------------------------
下面來完成一個傳上傳圖片,這和前面的上傳檔案沒有什麼區別.只不過操作檔案的時候使用的流對象是位元組流而已! 我們來體驗一下!
//伺服器端public class TcpImage {public static void main(String[] args) throws Exception {ServerSocket server = new ServerSocket(10909);Socket client = server.accept();// 擷取用戶端的輸入資料流InputStream is = client.getInputStream();// 擷取用戶端的輸出資料流OutputStream out = client.getOutputStream();// 檔案存放的位置OutputStream os = new FileOutputStream("server.jpg");byte[] buffer = new byte[1024];int len = 0;while ((len = is.read(buffer)) != -1) {os.write(buffer, 0, len);}// 反饋資訊給用戶端BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));bw.write("圖片上傳完成");bw.flush();os.close();client.close();server.close();}}
// 用戶端class Client {public static void main(String[] args) throws Exception {// 建立用戶端服務物件Socket socket = new Socket("192.168.1.102", 10909);InputStream in = new FileInputStream("D:\\imagetest\\desk.jpg");// 擷取用戶端的輸出資料流對象OutputStream os = socket.getOutputStream();// 擷取用戶端的輸入資料流對象InputStream is = socket.getInputStream();byte[] buffIn = new byte[1024];int len = 0;while ((len = in.read(buffIn)) != -1) {os.write(buffIn, 0, len);}// 告訴伺服器我已經發送完畢socket.shutdownOutput();BufferedReader br = new BufferedReader(new InputStreamReader(is));String message = br.readLine();System.out.println(message);in.close();socket.close();}}
我們知道這是單線程,一次只能服務一個用戶端.當用戶端A串連後,被伺服器端擷取到,伺服器執行具體流程,這時B用戶端串連,只能等待,因為伺服器的端還沒有處理完用戶端A的請求,如果很多用戶端都要和我這個伺服器通訊的話,怎麼辦呢?最好伺服器端將每個用戶端封裝到不同的線程裡,這樣就可以處理多個用戶端請求.現在我們來實現一下,多個用戶端實現檔案上傳.
public class TcpThreads implements Runnable {private Socket socket;public TcpThreads(Socket socket) {this.socket = socket;}public void run() {int count = 1;String ip = socket.getInetAddress().getHostAddress();try {System.out.println(ip + "............connected");// 擷取用戶端的輸入資料流File file = new File(ip + ".jpg");// 如果檔案已經存在,則修改名稱使之加一,直到名稱不等while (file.exists())file = new File(ip + "(" + (count++) + ")" + ".jpg");InputStream is = socket.getInputStream();// 擷取用戶端的輸出資料流OutputStream out = socket.getOutputStream();// 檔案存放的位置OutputStream os = new FileOutputStream(file);byte[] buffer = new byte[1024];int len = 0;while ((len = is.read(buffer)) != -1) {os.write(buffer, 0, len);}// 反饋資訊給用戶端BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out));bw.write("圖片上傳完成");bw.flush();os.close();socket.close();} catch (Exception e) {throw new RuntimeException(ip + "上傳失敗");}}}
class ClientImage {public static void main(String[] args) throws Exception {if (args.length != 1) {System.out.println("請輸入一個檔案有效路徑");return;}File file = new File(args[0]);if (!(file.exists() && file.isFile())) {System.out.println("該檔案已經存在,或者不是一個檔案");return;}long maxSize = 1024 * 1024 * 5;if (file.length() > maxSize) {System.out.println("檔案不能大於5M");return;}if(!file.getName().endsWith(".jpg")){System.out.println("檔案只能是JPG");return;}// 建立用戶端服務物件Socket socket = new Socket("192.168.1.102", 12345);InputStream in = new FileInputStream(file);// 擷取用戶端的輸出資料流對象OutputStream os = socket.getOutputStream();// 擷取用戶端的輸入資料流對象InputStream is = socket.getInputStream();byte[] buffIn = new byte[1024];int len = 0;while ((len = in.read(buffIn)) != -1) {os.write(buffIn, 0, len);}// 告訴伺服器我已經發送完畢socket.shutdownOutput();BufferedReader br = new BufferedReader(new InputStreamReader(is));String message = br.readLine();System.out.println(message);in.close();socket.close();}}
class ServerImage {public static void main(String[] args) throws Exception {ServerSocket server = new ServerSocket(12345);while (true) {Socket socket = server.accept();// 阻塞式方法,當擷取到用戶端對象,就建立線程new Thread(new TcpThreads(socket)).start();}}}
現在就可以對多個用戶端服務了,看服務端的代碼,while(true)說明伺服器是一直開著的,
public static void main(String[] args) throws Exception {ServerSocket server = new ServerSocket(12345);while (true) {Socket socket = server.accept();// 阻塞式方法,當擷取到用戶端對象,就建立線程new Thread(new TcpThreads(socket)).start();}}
又因為accept是阻塞式方法,當沒有用戶端請求伺服器時,伺服器一直處於阻塞狀態,直到有用戶端請求,如果有多個用戶端訪問,也會建立一個新線程為該用戶端服務,因為伺服器處理代碼已經封裝到了run()方法裡面去了!現在實現一個與上面程式類似的小程式,-----TCP 用戶端並發登入 每次看完老師寫完代碼,自己獨立寫出來,一開始總是報一些錯誤,只要自己仔細的分析,問題還是可以解決的,如果老師些一行你寫一行我覺得這樣的效果不好,自己只是,照著他實現了一遍,在腦裡面的印象不是特別的深,如果自己獨立寫出來,雖然可能耗費幾倍的時間,但是已經融入了自己的理解,也提高了自己解決問題的能力.當自己寫完了,再和老師的對照,然後比較那個更好一些!
class ServerLogon implements Runnable {private Socket socket;public ServerLogon(Socket socket) {this.socket = socket;}public void run() {String ip = socket.getInetAddress().getHostAddress();try {//列印用戶端的ipSystem.out.println(ip + "............. connected!");BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);// 只有三次嘗試的機會for (int i = 0; i < 3; i++) {BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("user.txt")));String username = br.readLine();//如果使用者直接退出if (username == null) {break;}String line = null;boolean flag = false;while ((line = reader.readLine()) != null) {if (line.equals(username)) {flag = true;break;}}//如果使用者名稱相同if (flag) {System.out.println(username + "登入成功");pw.println("歡迎登入");}else {System.out.println(username + "嘗試登入");pw.println("無效的使用者名稱");}reader.close();}socket.close();} catch (IOException e) {throw new RuntimeException(ip + "串連失敗");}}}
class UserClient {public static void main(String[] args) throws Exception {Socket socket = new Socket("192.168.1.102", 11111);PrintWriter bw = new PrintWriter(socket.getOutputStream(), true);BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));BufferedReader br = new BufferedReader(new InputStreamReader(System.in));for (int i = 0; i < 3; i++) {String name = br.readLine();System.out.println(name);//如果用戶端按Ctrl+cif (name == null)break;bw.println(name);String message = in.readLine();System.out.println(message);if (message.contains("歡迎")) {break;}}br.close();socket.close();}}
public class TcpLogon {public static void main(String[] args) throws IOException {ServerSocket server = new ServerSocket(11111);while (true) {Socket socket = server.accept();new Thread(new ServerLogon(socket)).start();}}}
使用者資訊如下所示:
我們寫了這麼多的用戶端與服務端,程式不管是多線程還是單線程,它的總體思想是不變的,他們都是和流一起使用的,管伺服器多麼複雜,基本的原理還是這樣的
學好這些,有助於我們以後理解學習和使用伺服器如Tomcat等web伺服器!
-----------------
Java培訓 Android培訓 期待與您的交流----------------------------