SocketTimeoutException: Изчакване за четене

Това е проста клиент/сървър базирана пинг/понг програма. За съжаление, 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<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();}

    }
}

СЪРВЪРНА ЗАДАЧА

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

КЛИЕНТ

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

    }

}

КЛИЕНТСКА ЗАДАЧА

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

}

person Eriassa    schedule 05.11.2014    source източник


Отговори (1)


Проблемът е във взаимодействието между вашето използване на 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);
person dan.m was user2321368    schedule 05.11.2014
comment
Благодаря много, особено за обяснението! Сега работи и научих още нещо за работата в мрежа! ^^ - person Eriassa; 05.11.2014