解決Java中socket使用getInputStream()阻塞問題
socket使用getInputStream()阻塞
今天用socket進行編程練習時,發現程序到瞭getInputStream()這裡就進行不下去瞭
Socket socket = new Socket("127.0.0.1", 800); ObjectInputStream reader = new ObjectInputStream(socket.getInputStream()); System.out.println("a"); ObjectOutputStream writer = new ObjectOutputStream(socket.getOutputStream());
就這樣的一個測試代碼,a不會打印出來
後來發現是getInputStream()會一直阻塞在那裡阻塞
我把兩行代碼調瞭一下就好瞭,還不太清楚原因,先記下來
Socket socket = new Socket("127.0.0.1", 800); ObjectOutputStream writer = new ObjectOutputStream(socket.getOutputStream()); System.out.println("a"); ObjectInputStream reader = new ObjectInputStream(socket.getInputStream());
用線程解決Socket的getInputStream阻塞
1.背景
在Socket通信中,當我們希望傳輸對象時,往往會用到輸入/輸出對象流。
ObjectInputStream in=new ObjectInputStream(socket.getInputStream()); ObjectOutputStream out=new ObjectOutputStream(socket.getOutputStream());
2.問題
當程序調用socket.getInputStream()程序被被卡住。
3.原因
socket.getInputStream()方法會導致程序阻塞,直到inputStream收到對方發過來的報文消息,程序才會繼續往下執行。
public ObjectInputStream(InputStream in) throws IOException的官方API顯示:
Creates an ObjectInputStream that reads from the specified InputStream. A serialization stream header is read from the stream and verified. This constructor will block until the corresponding ObjectOutputStream has written and flushed the header. [1]
4.解決辦法
用線程的方式處理輸入流。以下為示例代碼:
//===============客戶端代碼 SocketClient.java=====================
import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; import java.net.UnknownHostException; public class SocketClient { private Socket socket; private ObjectOutputStream out; private ObjectInputStream in; public SocketClient(){ try { socket=new Socket("localhost",8081); out=new ObjectOutputStream(socket.getOutputStream()); ReadThread readThread=new ReadThread(); readThread.start(); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void sendMessage(String msg){ System.out.println("send message:"+msg); try { out.writeObject(msg); out.flush(); } catch (IOException e) { e.printStackTrace(); } } class ReadThread extends Thread{ boolean runFlag=true; public void run(){ try { in=new ObjectInputStream(socket.getInputStream()); } catch (IOException e1) { e1.printStackTrace(); } while(runFlag){ if(socket.isClosed()){ return; } try { Object obj=in.readObject(); if(obj instanceof String){ System.out.println("Client recive:"+obj); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } public void exit(){ runFlag=false; } } public static void main(String[] args) { SocketClient socketClient=new SocketClient(); System.out.println("build socketClient"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } socketClient.sendMessage("Hello first."); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } socketClient.sendMessage("Hello second."); } }
//============服務器端代碼 SocketService.java===========
import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.util.Date; public class SocketService { ServerSocket serverSocket; public SocketService(){ try { serverSocket=new ServerSocket(8081); while(true){ Socket socket=serverSocket.accept(); SocketServiceThread sst=new SocketServiceThread(socket); sst.start(); } } catch (IOException e) { e.printStackTrace(); } } class SocketServiceThread extends Thread{ Socket socket; ObjectInputStream in; ObjectOutputStream out; boolean runFlag=true; public SocketServiceThread(Socket socket){ if(null==socket){ runFlag=false; return; } this.socket=socket; try { out=new ObjectOutputStream(socket.getOutputStream()); } catch (IOException e) { e.printStackTrace(); } } public void run(){ if(null==socket){ System.out.println("socket is null"); return; } try { in=new ObjectInputStream(socket.getInputStream()); while(runFlag){ if(socket.isClosed()){ System.out.println("socket is closed"); return; } try { String obj=(String)in.readObject(); if(obj instanceof String){ System.out.println("Server recive:"+obj); Date date=new Date(); out.writeObject("["+date+"]"+obj); out.flush(); } else{ System.out.println("Server recive:"+obj); } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SocketException e){ e.printStackTrace(); return; } catch (IOException e){ e.printStackTrace(); } } } catch (IOException e1) { e1.printStackTrace(); return; } catch (Exception e){ return; } } public void exit(){ runFlag=false; } } public static void main(String[] args) { System.out.println("===============start service==============="); new SocketService(); } }
5.Socket通信註意事項
(1).writeXXX()方法後一般用flush()來把緩存內容發送出去。
(2).發送對象時,對象必須串行化,即該對象需要實現Serializable接口。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。