欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java Socket通信介紹及可能遇到的問題解決

 更新時間:2017年10月11日 09:56:13   作者:搖頭耶穌  
最近在學習Java中的Socket通信,所以下面這篇文章主要給大家介紹了關于Java Socket通信介紹及可能遇到問題的解決方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面隨著小編來一起看看吧。

前言

本文主要給大家介紹了關于Java中Socket通信的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

Java中基于TCP協議實現網絡通信的兩個類:客戶端的Socket和服務器端的ServerSocket。

Socket通信模型如圖所示:

不管Socket通信的功能有多復雜,任何socket通信過程的基本結構都是一樣的。

其基本步驟為:

      ①分別在客戶端和服務器端創(chuàng)建Socket和ServerSocket實例;服務器端通過.accept()方法等待請求并阻塞。請求收到后,建立連接Socket對象。

      ②通過getInputStream和getOutputStream方法分別在客戶端和服務器端打開輸入輸出流

      ③利用IO流進行讀寫操作

      ④關閉所有的流資源和套接字資源。

其中,編程工作主要集中在第三步,其他的部分代碼基本相同。所有步驟都可能拋出IO異常!

我在編寫一個簡單的socket程序時,使用的Socket通信出現了一個問題:我在客戶端寫入的數據,在服務器端無法輸出。當我從客戶端斷開連接時,之前寫入的所有數據立刻在服務器端輸出出來了。經過反復的驗證和求解,以下是我的結論和解決方法。希望有同樣問題的小伙伴看完可以解決問題。

通過一端的Socket建立了PrintWriter類來寫入數據,通過另一端的Socket建立了BufferedReader類來讀取數據并輸出。

如果數據寫入后沒有被顯示,可能的原因有兩種:

一、寫入的數據存儲在緩沖區(qū)中,沒有被寫入IO流中:

如果不主動的干涉,寫入的數據會一直堆在緩沖區(qū)中,直到緩沖區(qū)滿了引發(fā)JVM自動刷新緩沖區(qū)。顯然這不符合我們的需求。對于這種情況,PrintWriter類提供了flush()方法來強制刷新緩沖區(qū),將緩沖區(qū)數據寫入IO流中。另外,PrintWriter類的構造器有一個參數”boolean autoflush“,這個參數默認為false,如果設置為true,則會開啟自動刷新緩沖區(qū)功能。但是請注意,這里的自動刷新是有觸發(fā)條件的,那就是:PrintWriter類寫入數據的方法必須是println、printf或者format方法時,才會觸發(fā)自動刷新。如果是調用write()這類方法寫入數據,是不會觸發(fā)自動刷新的!總結起來,就是三點:autoflush參數設置,write和println方法的選擇,flush方法的使用。對這三個進行組合,就能保證在Socket通信的某一端寫入數據時,數據一定能成功地寫入到IO流中!

二、讀取數據使用了readLine()方法,該方法沒有正常的結束:

請注意,BufferedReader類的readLine()方法是一個阻塞函數!也就是說,這個方法本身是讀取一行數據,但是它自己識別不了什么叫做“一行”!當調用該方法讀取完一段數據后,它會阻塞,而不會return它的讀取數據。這就是為什么有的時候明明已經刷新了緩沖區(qū)正確的寫入數據了,還是通過輸入流讀取數據并顯示出來的原因。

對于readLine()方法,它解除阻塞、正確結束并返回讀取的值,只有以下幾種情況:

      ①讀取的數據里含有回車符"\r"或者換行符"\n"或者回車換行符"\r\n";

      ②讀取的數據是在另一端通過println方法寫入的,因為println方法自帶換行符;

      ③BufferedReader類的緩沖區(qū)滿了,那么JVM會自動刷新緩沖區(qū)從而釋放“積攢”的數據(但是鑒于默認緩沖區(qū)大小為8192個字符,對于小數據量的通信,顯然觸發(fā)不了);

      ④對于讀取的數據,寫入這些數據的流發(fā)生異?;蛘咧苯雨P閉,那么readLine()就會把它吃的數據全部吐出來。這就剛好解釋了,為什么在我的程序中,斷開客戶端Socket連接,服務器端立刻輸出所有客戶端消息的原因。

綜上,在Socket通信過程中,保證某一端輸出流的緩沖被刷新,保證另一端的readLine方法能正常停止,即可解決寫入的數據在另一端無法輸出的問題。

以下是我修改后能成功運行的代碼,分別是服務器端Socket和客戶端Socket。

over!

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
public class ShakingServer{
 public static void main(String[] args) throws IOException {

 //創(chuàng)建服務器套接字實例,設置監(jiān)聽端口為2000
 ServerSocket server=new ServerSocket(2000);
 //開始監(jiān)聽客戶端的請求,并阻塞
 Socket socket=server.accept();
 //請求收到后,自動建立連接。通過IO流進行數據傳輸
 System.out.println("連接建立成功");

 OutputStream os=socket.getOutputStream();
 PrintWriter pw=new PrintWriter(new BufferedWriter(new OutputStreamWriter(os)),true);
 pw.write("歡迎訪問搖頭耶穌的世界!");
 pw.flush();
  //因為我關閉了輸出流,所以另一端的readLine方法才正常結束了
 socket.shutdownOutput();

 InputStream is=socket.getInputStream();
 InputStreamReader isr=new InputStreamReader(is);
 BufferedReader br=new BufferedReader(isr);
 while(true) {
  String str=br.readLine();
  if(str.equals("quit")) {
  break;
  }
  System.out.println("Client said: "+str);
 }
 socket.shutdownInput();
 //socket.shutdownOutput();
 socket.close();
 server.close();
 }
}
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.Socket;

public class ShakingClient{
 public static void main(String[] args) throws IOException{

 //創(chuàng)建客戶端的套接字,設置連接的服務器的IP地址和端口號
 Socket socket=new Socket("169.254.132.203",2000);
 //輸入流讀取服務器發(fā)送的信息
 BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
  //開啟自動刷新緩沖區(qū)
 PrintWriter pw=new PrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())),true);  
  //從鍵盤讀取數據
 BufferedReader ii=new BufferedReader(new InputStreamReader(System.in));
 System.out.println(br.readLine());
  //因為開啟了自動刷新,且調用的是println方法,所以可以不調用flush方法
 pw.println("請求進入搖頭耶穌的世界");
 //pw.flush();
 while(true) {
  String str=ii.readLine();
  //使用了回車符來保證另一端的readLine方法正常結束
  pw.write(str+"\r");
  pw.flush();
  //如果輸入quit則退出聊天室
  if(str.equals("quit")) {
  break;
  }
 }
 socket.shutdownInput();
 socket.shutdownOutput();
 socket.close();
 }
}

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關文章

  • Spring Boot 2.0 配置屬性自定義轉換的方法

    Spring Boot 2.0 配置屬性自定義轉換的方法

    這篇文章主要介紹了Spring Boot 2.0 配置屬性自定義轉換的方法,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-11-11
  • java并發(fā)編程StampedLock高性能讀寫鎖詳解

    java并發(fā)編程StampedLock高性能讀寫鎖詳解

    這篇文章主要為大家介紹了java并發(fā)編程StampedLock高性能讀寫鎖的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-05-05
  • Java使用正則表達式提取XML節(jié)點內容的方法示例

    Java使用正則表達式提取XML節(jié)點內容的方法示例

    這篇文章主要介紹了Java使用正則表達式提取XML節(jié)點內容的方法,結合具體實例形式分析了java針對xml格式字符串的正則匹配相關操作技巧,需要的朋友可以參考下
    2017-08-08
  • 使用springboot結合vue實現sso單點登錄

    使用springboot結合vue實現sso單點登錄

    這篇文章主要為大家詳細介紹了如何使用springboot+vue實現sso單點登錄,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • Mybatis Generator 獲取不到字段注釋的解決

    Mybatis Generator 獲取不到字段注釋的解決

    這篇文章主要介紹了Mybatis Generator 獲取不到字段注釋的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java設計模式中的策略(Strategy)模式解讀

    Java設計模式中的策略(Strategy)模式解讀

    這篇文章主要介紹了Java設計模式中的策略(Strategy)模式解讀,對象的某個行為,在不同場景有不同實現方式,可以將這些行為的具體實現定義為一組策略,每個實現類實現一種策略,在不同場景使用不同的實現,并且可以自由切換策略,需要的朋友可以參考下
    2023-10-10
  • Spring?AOP?創(chuàng)建代理對象詳情

    Spring?AOP?創(chuàng)建代理對象詳情

    這篇文章介紹了Spring?AOP?創(chuàng)建代理對象詳情,主要介紹AOP?創(chuàng)建代理對象和上下文相關的內容,下文分享具有一定的參考價值,需要的小伙伴可以參考一下
    2022-05-05
  • 類似Object監(jiān)視器方法的Condition接口(詳解)

    類似Object監(jiān)視器方法的Condition接口(詳解)

    下面小編就為大家?guī)硪黄愃芆bject監(jiān)視器方法的Condition接口(詳解)。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05
  • JavaMail實現發(fā)送郵件(QQ郵箱)

    JavaMail實現發(fā)送郵件(QQ郵箱)

    這篇文章主要為大家詳細介紹了JavaMail實現發(fā)送郵件(QQ郵箱),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • 非常實用的java萬年歷制作方法

    非常實用的java萬年歷制作方法

    這篇文章主要為大家詳細介紹了非常實用的java萬年歷制作方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-02-02

最新評論