socket.getInputSteam.read() does not throw when I close the socket from the client

旧街凉风 提交于 2020-01-06 23:40:31

问题


I am on windows 7 x64. I am writing a server which opens a thread for every incoming connection - the thread reads from the connection's input stream. The read() should block and throw an exception if the socket is closed(). It does not - just returns -1. If I do not close the connection from the client - just let the client terminate - I get a connection reset as excpected - but if I close() the connection from the client (or just the client's output stream for that matter) read() in the server thread does not throw - just returns -1. The docs are pretty clear on this :

public void close() throws IOException

Closes this socket.

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

Help

Working code :

Server :

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) {
                }
            }
        }
    }
}

Client :

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:


The bit of documentation you're referring to applies to threads on that machine, not remote threads. If you have thread A read()'ing on socket X, and thread B of the same process closes socket X, then an exception will be thrown for thread A's read call.

When a socket is close()'d on the the local machine, the remote machine can determine that there will be no more data coming over the socket so it returns -1 (see the read() documentation for InputStream). This is what is happening when you explicitly close the connection on the client. The server knows no more data will be coming so read() happily returns -1. There are no exceptional circumstances.

I'm guessing that when you let the client terminate without calling close() on the socket, the JVM or OS is sending a TCP RST instead of closing the connection nicely (sending TCP FIN). This causes the read() call on the server to throw an exception.



来源:https://stackoverflow.com/questions/8334045/socket-getinputsteam-read-does-not-throw-when-i-close-the-socket-from-the-clie

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!