解決Java中socket使用getInputStream()阻塞問題
socket使用getInputStream()阻塞
今天用socket進(jìn)行編程練習(xí)時(shí),發(fā)現(xiàn)程序到了getInputStream()這里就進(jìn)行不下去了
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());
就這樣的一個(gè)測(cè)試代碼,a不會(huì)打印出來
后來發(fā)現(xiàn)是getInputStream()會(huì)一直阻塞在那里阻塞
我把兩行代碼調(diào)了一下就好了,還不太清楚原因,先記下來
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通信中,當(dāng)我們希望傳輸對(duì)象時(shí),往往會(huì)用到輸入/輸出對(duì)象流。
ObjectInputStream in=new ObjectInputStream(socket.getInputStream()); ObjectOutputStream out=new ObjectOutputStream(socket.getOutputStream());
2.問題
當(dāng)程序調(diào)用socket.getInputStream()程序被被卡住。
3.原因
socket.getInputStream()方法會(huì)導(dǎo)致程序阻塞,直到inputStream收到對(duì)方發(fā)過來的報(bào)文消息,程序才會(huì)繼續(xù)往下執(zhí)行。
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."); } }
//============服務(wù)器端代碼 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通信注意事項(xiàng)
(1).writeXXX()方法后一般用flush()來把緩存內(nèi)容發(fā)送出去。
(2).發(fā)送對(duì)象時(shí),對(duì)象必須串行化,即該對(duì)象需要實(shí)現(xiàn)Serializable接口。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
淺談@FeignClient中name和value屬性的區(qū)別
這篇文章主要介紹了@FeignClient中name和value屬性的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07一文搞懂Runnable、Callable、Future、FutureTask及應(yīng)用
一般創(chuàng)建線程只有兩種方式,一種是繼承Thread,一種是實(shí)現(xiàn)Runnable接口,在Java1.5之后就有了Callable、Future,這二種可以提供線程執(zhí)行完的結(jié)果,本文主要介紹了Runnable、Callable、Future、FutureTask及應(yīng)用,感興趣的可以了解一下2023-08-08Spring自帶的校驗(yàn)框架Validation的使用實(shí)例
今天小編就為大家分享一篇關(guān)于Spring自帶的校驗(yàn)框架Validation的使用實(shí)例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2019-03-03Java發(fā)送https請(qǐng)求并跳過ssl證書驗(yàn)證方法
最近在負(fù)責(zé)一個(gè)對(duì)接第三方服務(wù)的事情,在對(duì)接期間因?yàn)榈谌椒?wù)為https的請(qǐng)求,這篇文章主要給大家介紹了關(guān)于Java發(fā)送https請(qǐng)求并跳過ssl證書驗(yàn)證的相關(guān)資料,需要的朋友可以參考下2023-11-11MyBatis Plus整合Redis實(shí)現(xiàn)分布式二級(jí)緩存的問題
Mybatis內(nèi)置的二級(jí)緩存在分布式環(huán)境下存在分布式問題,無法使用,但是我們可以整合Redis來實(shí)現(xiàn)分布式的二級(jí)緩存,這篇文章給大家介紹MyBatis Plus整合Redis實(shí)現(xiàn)分布式二級(jí)緩存,感興趣的朋友跟隨小編一起看看吧2023-11-11IDEA安裝阿里巴巴編碼規(guī)范插件的兩種方式詳解(在線安裝和離線安裝)
這篇文章主要介紹了IDEA安裝阿里巴巴編碼規(guī)范插件的兩種方式詳解(在線安裝和離線安裝),本文通過截圖給大家展示的非常詳細(xì),需要的朋友可以參考下2021-09-09Eclipse 使用Maven構(gòu)建SpringMVC項(xiàng)目
本文主要介紹在Eclipse下創(chuàng)建Maven項(xiàng)目構(gòu)建SpringMVC框架的過程,講解的比較詳細(xì),需要的朋友可以參考下。2016-06-06