java - 当我从客户端关闭套接字时,socket.getInputStream.read() 不会抛出异常

标签 java sockets exception

我使用的是 Windows 7 x64。我正在编写一个服务器,它为每个传入连接打开一个线程 - 该线程从连接的输入流中读取。如果套接字被关闭(),read()应该阻塞并抛出异常。它不 - 只是返回 -1。如果我不关闭来自客户端的连接 - 只需让客户端终止 - 我会按预期重置连接 - 但如果我 close() 来自客户端的连接(或只是客户端的输出流) read()在服务器线程中不会抛出异常 - 只是返回-1docs对此非常清楚:

public void close() throws 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");
    }
}

最佳答案

您所指的文档适用于该计算机上的线程,而不是远程线程。如果线程 A 在套接字 X 上进行 read(),并且同一进程的线程 B 关闭了套接字 X,则线程 A 的读取调用将引发异常。

当本地计算机上的套接字被 close() 时,远程计算机可以确定不再有数据通过套接字传入,因此它返回 -1(请参阅 InputStream 的 read() 文档)。这就是当您显式关闭客户端上的连接时发生的情况。服务器知道不会有更多数据到来,因此 read() 很乐意返回 -1。没有特殊情况。

我猜测,当您让客户端终止而不在套接字上调用 close() 时,JVM 或操作系统将发送 TCP RST,而不是很好地关闭连接(发送 TCP FIN)。这会导致服务器上的 read() 调用抛出异常。

关于java - 当我从客户端关闭套接字时,socket.getInputStream.read() 不会抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8334045/

相关文章:

java - 生成文件并在map函数中写入

Java的随机值每次都不同

c - 套接字io函数send()和recv()的函数指针

c - 从结构体发送数据,套接字编程

java - 在 Java 中使用 .hasNextInt() 进行一些简单的异常处理有问题吗?

c++ - out_of_range、range_error 和 over/underflow_error 之间的区别?

java - Mysql JDBC - 未输入 ResultSet + 不正确的编号。行数

java - Guice 可以初始化 bean 吗?

javascript - info - 未处理的 socket.io url

c++ - 抛出的(默认)构造函数中的异常保证应该是什么?