当我从客户端关闭套接字时,socket.getInputSteam.read()不会抛出 [英] socket.getInputSteam.read() does not throw when I close the socket from the client

查看:121
本文介绍了当我从客户端关闭套接字时,socket.getInputSteam.read()不会抛出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Windows 7 x64上。我正在写一个服务器,为每个传入连接打开一个线程 - 线程从连接的输入流读取。如果套接字是closed(),那么read()就会阻塞并抛出一个异常。它不 - 只返回-1。如果我没有关闭客户端的连接 - 只需让客户端终止 - 我得到一个重新连接重新设置,但如果我关闭()客户端的连接(或只是客户端的输出流)read()在服务器线程中不抛出 - 只返回 -1 文档是很清楚这一点:


public void close()
throws IOException

 关闭此套接字。 

当前在此套接字上I / O操作中阻塞的线程将抛出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 args []){
CloseTest bs = new CloseTest(8082);
bs.base_station_activate();
}
public class BaseStationClientHandler实现Runnable {
private final Socket clientSocket;

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

public void run(){
String debug_message = null;
try {
InputStream in = clientSocket.getInputStream();
//读取消息并回复
String s =;
char x;
int r;
server:while(true){
try {
while((r = in.read())!=(int)'%'){
if(r = = -1){
debug_message =Stream / socket .closed() - 异常未抛出(WHYYYYY ????)by client;
System.out.println(debug_message);
中断服务器;
}
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;
中断服务器;
}
s =;
} // server
} catch(IOException ex){
System.out.println(客户端处理程序中的IOexception - 检查是否抛出);
} 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>();
尝试{
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); //确保服务器线程在read()
// connection.close()中被阻止; //如果我注释这个,我看到服务器的连接重置消息,当这个主要终止
//最后注释它,并移动结束到最后确保服务器线程被阻止在read()
}
} catch(Exception ex){
ex.printStackTrace();
}
finally {
//如果我注释*为* out我看到服务器的connection_reset消息,当这个主要终止
(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上,并且同一进程的线程B关闭套接字X,那么线程A的读取调用将抛出异常。



当本地机器上的套接字关闭()'d时,远程机器可以确定没有更多的数据通过套接字传递,所以返回-1(参见InputStream的read()文档)。当您明确关闭客户端上的连接时,会发生这种情况。服务器知道没有更多的数据将来,所以read()愉快地返回-1。没有特殊情况。



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


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

解决方案

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.

这篇关于当我从客户端关闭套接字时,socket.getInputSteam.read()不会抛出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆