解决Java中socket使用getInputStream()阻塞问题
作者:godelgnis
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接口。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。