Android - Socket Connected即使它不能

apm*_*991 5 sockets android

首先,我知道你的想法,这是一个奇怪的问题,似乎不可能是真的,但在这里,我出这个...

该项目是一个项目,它通过套接字发送一个字节数组,并从套接字接收数据.我目前正致力于保护.我想确保用户知道套接字何时无法连接...您可以在下面查看连接代码.

所以我有一个Android应用程序连接到世界其他地方办公室的Windows Server计算机上的可执行文件.套接字通过通常的IP地址和端口号连接.

我正在使用Android 5.0(棒棒糖)手机测试应用程序...

现在有足够的无聊的东西:如果我关闭服务器并完全关闭它并在wi-fi上测试它,那么套接字失败 - 这是正确的.它无法连接,它会抛出一个SocketException.这很好,并按预期工作.现在如果我关闭wi-fi并使用移动数据(我在阳光明媚的英国使用o2!)然后出现问题,使用相同的代码,服务器仍然关闭,我不抛出SocketException,相反,代码简单认为它已连接在套接字上.连接线程在下面.

Thread StartConnection = new Thread()
        {
            @Override
            public void run()
            {

                int dstPort = 10600;

                socket = new Socket();
                try
                {
                    ipaddress = InetAddress.getByName(dstName);
                }
                catch (UnknownHostException uhe)
                {
                    uhe.printStackTrace();
                }

                j = new InetSocketAddress(IPString , dstPort);

                try
                {
                        socket.setKeepAlive(true);
                        socket.setReuseAddress(true);
                        socket.setTcpNoDelay(true);
                        socket.setSoTimeout(5000);
                        socket.connect(j, 5000);
                        connected = true;
                        outputstream = socket.getOutputStream();
                        DataThread();
                        SocketError = false;
                }
                catch (SocketException se)
                {
                    se.printStackTrace();
                }
                catch (IllegalArgumentException iae)
                {
                    iae.printStackTrace();
                }
                catch (IOException ioe)
                {
                    ioe.printStackTrace();
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        };
        StartConnection.start();
Run Code Online (Sandbox Code Playgroud)

socket.connect(j, 5000); 
Run Code Online (Sandbox Code Playgroud)

工作正常没有套接字错误.没有超时.

outputstream = socket.getOutputStream(); 
Run Code Online (Sandbox Code Playgroud)

也有效.我得到了"java.net.PlainSocketImpl$PlainSocketOutputStream@48e6f6e"的结果,这也很好.

socket.getInputStream() 返回"java.net.PlainSocketImpl$PlainSocketInputStream@1ea305a5"

Gar*_*ght 3

这很有趣。我一直在测试并且可以复制您所描述的行为。

首先,这里得票最高的答案提供了关于 Java Socket API 的很好的讨论:

Java套接字API:如何判断连接是否已关闭?

由此,我想知道尝试从套接字读取一个字节是否允许我们检查它是否真的打开

// Endpoint that does not exist
Socket socket = new Socket("1.2.3.4", 1234);
InputStream tmpIn = socket.getInputStream();
int result = tmpIn.read();
Log.i("SocketTest", "read() result: " + result);
Run Code Online (Sandbox Code Playgroud)

在端点无效的情况下,我发现调用read()大约 10 秒后返回 -1。

在 IP 和端口上有侦听器的情况下,对 的调用read()似乎会无限期地阻塞,直到发生某些情况,例如实际从服务器接收数据,或失去互联网连接等。

基于这种差异,我将此测试包装到一个新类中:

public class VerifiedSocket extends Socket {

    public VerifiedSocket(String ip, int port, int millisecondTimeout) throws UnknownHostException, IOException{
        super(ip,port);

        ReadThread tryRead = new ReadThread();      
        tryRead.start();
        try {
            tryRead.join(millisecondTimeout);
        } catch (InterruptedException e) {
        }
        if(tryRead.getReadValue()==-1){
            // We read -1 so assume endpoint invalid
            throw new IOException("Endpoint is invalid");
        }       
    }

    private class ReadThread extends Thread{
        private int readValue = 512; // Impossible byte value

        @Override
        public void run(){              
            try {
                InputStream input = getInputStream();
                readValue = input.read();
            } catch (IOException e) {                   
            }               
        }

        public int getReadValue(){
            return readValue;
        }
    }       
}
Run Code Online (Sandbox Code Playgroud)

然后测试如下:

try {
    VerifiedSocket socket = new VerifiedSocket("1.2.3.4", 1234, 20000);
    Log.i("SocketTest", "Endpoint is valid");
    socket.close();
} catch (UnknownHostException e) {      
    Log.e("SocketTest", e.getLocalizedMessage());
} catch (IOException e) {       
    Log.e("SocketTest", e.getLocalizedMessage());
}
Run Code Online (Sandbox Code Playgroud)

如果我在 Wifi 上使用无效端点,则构造函数VerifiedSocket会抛出超时异常。如果我在移动数据上使用无效端点,它会抛出 IOException 并显示“端点无效”消息。不完美,但希望对你有帮助。