SocketTimeoutException:读取超时

这是一个简单的基于客户端/服务器的ping / pong程序。 不幸的是,IT不起作用并显示以下错误消息:

java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(Unknown Source) at java.net.SocketInputStream.read(Unknown Source) at sun.nio.cs.StreamDecoder.readBytes(Unknown Source) at sun.nio.cs.StreamDecoder.implRead(Unknown Source) at sun.nio.cs.StreamDecoder.read(Unknown Source) at java.io.InputStreamReader.read(Unknown Source) 

它停在CLIENT TASK 30行,实际上客户端没有读取服务器发送的内容。 这里的代码:

服务器

 package serverClient; import java.net.*; import java.io.*; import java.util.concurrent.*; public class Server { public static void main(String[]args){ ExecutorService esp= Executors.newFixedThreadPool(50); try(ServerSocket ss= new ServerSocket(1027)){ while(true){ try{ Socket s=ss.accept(); Callable task=new ServerTask(s); esp.submit(task); } catch(BindException be){} catch(ConnectException ce){} catch(NoRouteToHostException nrthe){} catch(IOException ioe){ioe.printStackTrace();} } } catch(Exception e){e.printStackTrace();} } } 

服务器任务

 package serverClient; import java.util.concurrent.*; import java.net.*; import java.io.*; public class ServerTask implements Callable  { Socket s; ServerTask(Socket s){ this.s=s; } public Void call(){ BufferedWriter writer=null; BufferedReader reader=null; try{ reader=new BufferedReader(new InputStreamReader(s.getInputStream())); writer=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); int i=0; StringBuilder sb=new StringBuilder(); while((i=reader.read())!=-1){ sb.append((char)i); } System.out.println("The client sends: "+sb); writer.write("pong"); writer.flush(); } catch(IOException ioe){ioe.printStackTrace();} finally{ try { writer.close(); } catch (IOException ioe) {ioe.printStackTrace();} if(reader!=null){ try{ reader.close(); } catch(IOException ioe){ioe.printStackTrace();} } try{ s.close(); } catch(IOException ioe){ioe.printStackTrace();} } return null; } } 

客户

 package serverClient; import java.io.IOException; import java.net.*; import java.util.concurrent.*; public class Client { public static void main(String[] args) { ExecutorService es= Executors.newSingleThreadExecutor(); try { Socket s= new Socket(InetAddress.getLocalHost(),1027); try { s.setSoTimeout(50000); } catch(SocketException se){se.printStackTrace();} Callable task=new ClientTask(s); es.submit(task); } catch (UnknownHostException uhe) {uhe.printStackTrace();} catch (IOException ioe) {ioe.printStackTrace();} } } 

客户任务

 package serverClient; import java.util.concurrent.*; import java.net.*; import java.io.*; public class ClientTask implements Callable { Socket s; ClientTask(Socket s){ this.s=s; } public Void call(){ BufferedWriter writer=null; BufferedReader reader=null; try{ writer=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); reader=new BufferedReader(new InputStreamReader(s.getInputStream())); writer.write("ping"); writer.flush(); int i=0; StringBuilder sb=new StringBuilder(); while((i=reader.read())!=-1){ System.out.println("I'm reading."); sb.append((char)i); } System.out.println("The server sends: "+sb); } catch(IOException ioe){ ioe.printStackTrace();} finally{ try { writer.close(); } catch (IOException ioe) {ioe.printStackTrace();} if(reader!=null){ try{ reader.close(); } catch(IOException ioe){ioe.printStackTrace();} } try{ s.close(); } catch(IOException ioe){ioe.printStackTrace();} } return null; } } 

问题在于在while循环中使用BufferedReader.read()与从连接另一端处理套接字的方式之间的交互。

..read()只会在它正在读取的流结束时返回-1,这在本例中基本上意味着套接字已关闭。 在套接字关闭之前,服务器只是在read阻塞,等待客户端发送另一个字符。 由于服务器在read阻塞,它将永远不会发送’pong’。 客户端阻止自己的读取,但最终达到了超时。

TCP套接字用于处理数据流。 如果要使用它来发送离散消息,则需要在客户端和服务器之间强制执行协议,以便每个人都知道完整消息何时到达。 在这种情况下,客户端和服务器可以就使用终结符来约定,以指定消息是完整的。 例如,他们可以同意在每条消息之后发送\n作为终止符。

因此,例如,在您的客户端中,相关代码如下所示:

 writer.write("ping"); writer.write('\n'); writer.flush(); int i=0; StringBuilder sb=new StringBuilder(); while((i=reader.read())!=-1){ char c = (char)i; if(c == '\n') break; sb.append(c); } System.out.println("The server sends: "+sb);