您好,登錄后才能下訂單哦!
這篇文章主要介紹了Java socket通訊實現過程及問題解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
本來是打算驗證java socket是不是單線程操作,也就是一次只能處理一個請求,處理完之后才能繼續處理下一個請求。但是在其中又發現了許多問題,在編程的時候需要十分注意,今天就拿出來跟大家分享一下。
首先先建立一個服務端代碼,運行時也要先啟動此程序。
package com.test.some.Socket; import java.io.*; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; /** * @Description: socket服務端代碼 * @Author: haoqiangwang3 * @CreateDate: 2020/1/9 */ public class MySocketServer1 { // 服務器監聽端口 private static int port = 8081; public static void main(String[] args) throws InterruptedException { try { //1.得到一個socket服務端 ServerSocket serverSocket = new ServerSocket(port); while (true) { // 2.等待socket客戶端的請求。accept方法在有連接請求時才會返回 System.out.println("等待客戶端請求。。。"); Socket socket = serverSocket.accept(); System.out.println("客戶端請求來了。。。"); // 3.獲取socket輸入流 InputStream inputStream = socket.getInputStream(); /* BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); System.out.println("接收到的請求數據為:" + bufferedReader.readLine());*/ // 讀取請求內容的緩沖區 byte[] bytes = new byte[1024]; int length = 0; StringBuilder sb = new StringBuilder(); //獲取客戶端請求的內容 while ((length = inputStream.read(bytes)) != -1) { sb.append(new String(bytes, 0, length, "utf-8")); } System.out.println("接收到的請求數據為:" + sb.toString()); //Thread.sleep(50000); // 4.獲取socket輸出流 OutputStream outputStream = socket.getOutputStream(); PrintWriter printWriter = new PrintWriter(outputStream); String backStr = "服務端接收到了請求"; printWriter.write(new String(backStr.getBytes(), "utf-8")); printWriter.flush(); //5.關閉資源 //bufferedReader.close(); inputStream.close(); printWriter.close(); outputStream.close(); socket.close(); } } catch (IOException e) { System.err.println("socket監聽失敗!" + e); } } }
此代碼模擬了正常系統成socket服務端的方式,就是一個無限循環監聽我們綁定的端口,當有客戶端請求來了之后進行處理。
下面就是客戶端請求代碼
package com.test.some.Socket; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; /** * @Description: socket客戶端代碼 * @Author: haoqiangwang3 * @CreateDate: 2020/1/9 */ public class MySocketClient1 { //socket請求ip地址 private static String host = "127.0.0.1"; //socket請求端口 private static int port = 8081; public static void main(String[] args) { try { //1.建立一個客戶端 Socket socket = new Socket(host, port); //2.得到socket輸出流 OutputStream outputStream = socket.getOutputStream(); PrintWriter printWriter = new PrintWriter(outputStream); String sendStr = "發送數據1"; //發送數據 printWriter.write(sendStr); printWriter.flush(); socket.shutdownOutput(); //3.得到socket輸入流 InputStream inputStream = socket.getInputStream(); StringBuilder sb = new StringBuilder(); byte[] bytes = new byte[1024]; while (inputStream.read(bytes) != -1) { sb.append(new String(bytes, "utf-8")); } System.out.println("接收到的返回數據為:" + sb); //4.關閉資源 printWriter.close(); outputStream.close(); inputStream.close(); socket.close(); } catch (Exception e) { System.err.println("socket請求失敗" + e); } } }
客戶端代碼主要就是向服務端發送數據,然后等待服務端的響應,打印出服務端的響應內容。
最終打印結果如下。服務端:
客戶端:
首先明確幾個概念,下面將會用到。
flush()方法:用于清空緩沖區的數據流,進行流的操作時,數據先被讀到內存緩沖區中,然后再用數據寫到文件中。
socket.shutdownOutput()方法:他是一種單向關閉流的方法,即關閉客戶端的輸出流并不會關閉服務端的輸出流。通過shutdownOutput()方法只是關閉了輸出流,但socket仍然是連接狀態,連接并未關閉。
printWriter.close()方法:如果直接關閉輸入或者輸出流,即:in.close()或者out.close(),會直接關閉socket。
流中的關閉順序:一般情況下是:先打開的后關閉,后打開的先關閉。另一種情況:看依賴關系,如果流a依賴流b,應該先關閉流a,再關閉流b,例如處理流a依賴節點流b,應該先關閉處理流a,再關閉節點流b。當然完全可以只關閉處理流,不用關閉節點流。處理流關閉的時候,會調用其處理的節點流的關閉方法。如果將節點流關閉以后再關閉處理流,會拋出IO異常。
下面總結下我遇到的問題。
1.客戶端發送數據部分的代碼,printWriter.flush(); socket.shutdownOutput(); 這兩句代碼十分的重要,flush()方法如果不添加的話,服務端接收到的數據將為空,shutdownOutput()方法不添加的話,服務端將一直等待讀取客戶端的數據,不會往下進行,大家可以自測一下。我自己的理解是flush()的作用是為了把數據從內存中刷新到socket流中,shutdownOutput()方法是告訴服務端,我沒有東西要傳輸了,所以服務端也就會停止等待讀取客戶端發送的內容,程序就可以繼續向下走。
2.打開服務端中的sleep方法,在新建一個客戶端,同時開啟請求服務端,會發現服務端確實是一個連接一個連接的處理,所以這也是socket性能所在的問題。
3.如果不用字符流讀取,客戶端發送數據直接用outputStream.write(sendStr.getBytes());,可以發現此時不用調用flush()方法,但是socket.shutdownOutput()依然需要。這是因為直接讀取到socket的輸出流,并沒有讀到內存中。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。