java socket 阻塞模式_Java中Socket Read阻塞问题
本人來說并不熟悉JAVA語言,只是近期在分析某個簡單的java agent程序時,根據對應的代碼寫了一個對接的程序,兩者之間是典型的C/S socket編程。客戶端在向服務端發送相應的指令后,服務端(裝agent的主機)執行后會返回執行的數據給客戶端。在直接一行行收取數據時是正常的,但通過while循環時會卡住。
一、java讀取數據的兩種方式
從Socket上讀取對端發過來的數據一般有兩種方法:一種是按字節,一種是按字符。
1、按照字節流讀取
BufferedInputStream in = new BufferedInputStream(socket.getInputStream());
int r = -1;
List l = new LinkedList();
while ((r = in.read()) != -1) {
l.add(Byte.valueOf((byte) r));
}
2、按照字符流讀取
readLine()方法在進行讀取一行時,只有遇到回車(\r)或者換行符(\n)才會返回讀取結果,這就是“讀取一行的意思”。如果不指定buffer大小,則readLine()使用的buffer有8192個字符。在達到buffer大小之前,只有遇到"/r"、"/n"、"/r/n"才會返回。BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s;
while ((s = in.readLine()) != null) {
System.out.println("Reveived: " + s);
}
read()和readLine()都會讀取對端發送過來的數據,如果不加while循環時,是不會存在異常阻塞的情況的。但在使用while后,如果無數據可讀,就會阻塞直到有數據可讀。或者到達流的末尾,這個時候分別返回-1和null。具體也可以參看segmentfault上別人的提問和回答。
使用while的好處就是對于返回數據較多的情況,比較方便,如果是直接readLine而不加while時,默認只能取得最后一行的數據;其壞處也顯而易見----阻塞等待。
二、異常處理
1、服務端處理
發送完后調用Socket的shutdownOutput()方法關閉輸出流,這樣對端的輸入流上的read操作就會返回-1。注意不能調用socket.getInputStream().close()。這樣會導致socket被關閉。當然如果不需要繼續在socket上進行讀操作,也可以直接關閉socket。但是這個方法不能用于通信雙方需要多次交互的情況。
2、客戶端處理
為了防止read操作造成程序永久掛起,還可以給socket設置超時。例如下面的方法設定超時3秒:
socket.setSoTimeout(3000)
如果read()方法在設置時間內沒有讀取到數據,就會拋出一個java.net.SocketTimeoutException異常。
3、雙方約定
發送數據時,約定數據的首部固定字節數為數據長度。這樣讀取到這個長度的數據后,就不繼續調用read方法。或者雙方約定結尾字符信息,在讀取到相應信息時,客戶端主動發送斷開連接的信息,或者發送信號給服務端,由服務端斷開連接。
三、其他
我在實際使用中,使用了上面異常處理中提到的第三種。但在應用中如果由客戶端進行超進異常斷開連接時,客戶端在接收數據過程中會收到異常信息如下:
這時候就需要使用try……catch(Exception e)語句進行異常捕獲處理。最終一個完整的客戶端請求如下:
import java.io.*;
import java.net.*;
public class TalkClient {
public static void main(String args[]) {
try{
Socket socket=new Socket("127.0.0.1",4700);
//向本機的4700端口發出客戶請求
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
//由系統標準輸入設備構造BufferedReader對象
PrintWriter os=new PrintWriter(socket.getOutputStream());
//由Socket對象得到輸出流,并構造PrintWriter對象
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
//由Socket對象得到輸入流,并構造相應的BufferedReader對象
String readline;
readline=sin.readLine(); //從系統標準輸入讀入一字符串
while(!readline.equals("bye")){
//若從標準輸入讀入的字符串為 "bye"則停止循環
os.println(readline);
//將從系統標準輸入讀入的字符串輸出到Server
os.flush();
//刷新輸出流,使Server馬上收到該字符串
System.out.println("Client:"+readline);
//在系統標準輸出上打印讀入的字符串
System.out.println("Server:"+is.readLine());
//從Server讀入一字符串,并打印到標準輸出上
readline=sin.readLine(); //從系統標準輸入讀入一字符串
} //繼續循環
os.close(); //關閉Socket輸出流
is.close(); //關閉Socket輸入流
socket.close(); //關閉Socket
}catch(Exception e) {
System.out.println("Error"+e); //出錯,則打印出錯信息
}
}
}
總結
以上是生活随笔為你收集整理的java socket 阻塞模式_Java中Socket Read阻塞问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 7个和尚_经典故事:8个和尚与1串佛珠的
- 下一篇: 鼠标悬浮改变背景颜色