socket.getInputSteam.read () не выдает, когда я закрываю сокет от клиента - PullRequest
0 голосов
/ 01 декабря 2011

Я на Windows 7 х64. Я пишу сервер, который открывает поток для каждого входящего соединения - поток читает из входного потока соединения. Метод read () должен блокировать и выдавать исключение, если сокет закрыт (). Это не так - просто возвращает -1. Если я не закрываю соединение от клиента - просто позволяю клиенту завершиться - я получаю сброс соединения, как ожидается - но если я закрываю () соединение от клиента (или только выходного потока клиента в этом отношении) read () в серверном потоке не кидает - просто возвращает -1. В документах все ясно:

public void close () выдает IOException

Closes this socket.

Any thread currently blocked in an I/O operation upon this socket will throw a SocketException.

Помощь

Рабочий код:

Сервер:

import java.io.IOException;
import java.io.InputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class CloseTest {
    private int port;

    public CloseTest(int port) {
        this.port = port;
    }

    void base_station_activate() {
        ServerSocket baseStationListeningSocket=null;
        try {
            baseStationListeningSocket = new ServerSocket(this.port, 1, InetAddress.getByName("127.0.0.1"));
        } catch (IOException ex) {
        }

        main_server: while (true) {
            try {
                Socket clientSocket = baseStationListeningSocket.accept();
                BaseStationClientHandler ch = new BaseStationClientHandler(clientSocket);
                Thread myThread = new Thread(ch);
                myThread.start();
            } catch (IOException ex) {
                System.exit(1);
            } // main_server
            finally {
//                  baseStationListeningSocket.close()
            }
        }
    }
    public static void main(String args[]){
            CloseTest bs = new CloseTest(8082);
            bs.base_station_activate();
        }
    public class BaseStationClientHandler implements Runnable {
        private final Socket clientSocket;

        private BaseStationClientHandler(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }

        public void run() {
            String debug_message = null;
            try {
                InputStream in = clientSocket.getInputStream();
                // read message and respond
                String s = "";
                char x;
                int r;
                server: while (true) {
                    try {
                        while ((r = in.read()) != (int) '%') {
                            if (r == -1) {
                                debug_message = "Stream/socket .closed() - exception not thrown (WHYYYYY ????) by client";
                                System.out.println(debug_message);
                                break server;
                            }
                            x = (char) r;
                            s += x;
                        }
                        System.out.println(s);
                    } catch (SocketException socketException) {
                        System.out.println(socketException.getLocalizedMessage());  //  if connection reset (but not if Stream/socket .closed()) read throws !!!!!
                        debug_message = "socket_reset";
                        break server;
                    }
                    s = "";
                }   //server
            } catch (IOException ex) {
                System.out.println("IOexception in client handler - check if thrown by read");
            } finally {
                try {
                    clientSocket.close();
                } catch (IOException ex) {
                }
            }
        }
    }
}

Клиент:

import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Vector;

public class CloseTestClient {

    public CloseTestClient(int port, String ipAddress){
        Vector<Socket> connections = new Vector<Socket>();
        try {
            for(int i=0;i<20;i++){
                Socket connection = new Socket(InetAddress.getByName(ipAddress), port);
                connections.add(connection);
                OutputStream out = connection.getOutputStream();
                out.write( ("CONNECT#"+(i+1)+"#1%").getBytes());
                System.out.println("[CloseTestClient SENT]:"+"CONNECT#"+(i+1)+"#1%");
                Thread.sleep(1000); // to be sure the server threads are blocked in the read()
                // connection.close();  // if I comment this out I see the connection reset message from the server when this main terminates
                // commented it out finally and moved the closing at the end to be sure the server threads are blocked in read()
            }
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        finally{
            // if I comment *for* out I see the "connection_reset" message from the server when this main terminates
            for (Socket c : connections){
                try{
                    c.close();
                }catch(Exception ex){
                }
            }
        }
    }

    public static void main(String args[]){
        System.out.println("CloseTestClient run !");
        new CloseTestClient(8082,"127.0.0.1");
    }
}

1 Ответ

1 голос
/ 01 декабря 2011

Часть документации, на которую вы ссылаетесь, относится к потокам на этом компьютере, а не к удаленным.Если у вас есть поток read () для сокета X, а поток B того же процесса закрывает сокет X, тогда будет вызвано исключение для вызова чтения потока A.

Когда сокет закрыт ()На локальном компьютере удаленный компьютер может определить, что через сокет больше не будет поступать данных, поэтому он возвращает -1 (см. документацию read () для InputStream).Это то, что происходит, когда вы явно закрываете соединение на клиенте.Сервер знает, что больше данных не будет, поэтому read () с радостью возвращает -1.Нет никаких исключительных обстоятельств.

Я предполагаю, что когда вы позволяете клиенту завершить работу без вызова close () на сокете, JVM или ОС отправляет TCP RST вместо правильного закрытия соединения (отправка TCPПЛАВНИК).Это приводит к тому, что вызов read () на сервере вызывает исключение.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...