SocketTimeoutException:读取超时

Eri*_*ssa 5 java sockets networking socket-timeout-exception

这是一个简单的基于客户端/服务器的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)
Run Code Online (Sandbox Code Playgroud)

它停在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<Void> 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();}

    }
}
Run Code Online (Sandbox Code Playgroud)

服务器任务

package serverClient;

import java.util.concurrent.*;
import java.net.*;
import java.io.*;

public class ServerTask implements Callable <Void> {

    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;
    }
}
Run Code Online (Sandbox Code Playgroud)

客户

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<Void> task=new ClientTask(s);
            es.submit(task);

        } 
        catch (UnknownHostException uhe) {uhe.printStackTrace();} 
        catch (IOException ioe) {ioe.printStackTrace();}

    }

}
Run Code Online (Sandbox Code Playgroud)

客户任务

package serverClient;

import java.util.concurrent.*;
import java.net.*;
import java.io.*;

public class ClientTask implements Callable <Void>{

    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;
    }

}
Run Code Online (Sandbox Code Playgroud)

dan*_*368 7

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

..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);
Run Code Online (Sandbox Code Playgroud)