如何在不ping服务器的情况下检测到损坏的客户端套接字

时间:2019-02-10 19:26:49

标签: java sockets esp8266

我正在制作一个连接到ESP8266-01的客户端套接字应用程序,我唯一无法解决的事情是如何在不对服务器执行ping操作的情况下检测到损坏的套接字(ESP8266-01)。

到目前为止,我发现3种情况下,我认为套接字已损坏,因为客户端应用无法检测到它们:

1)突然断开ESP8266的电源,而没有正确关闭插座

2)断开连接我的应用程序和ESP8266的wifi。

3)从ESP8266调用AT + CIPCLOSE。

如果发生以上任何情况,并且我使用SendData()发送数据,则将引发并处理异常(情况1除外),在这种情况下,它根本不会被检测到。 我以前尝试过使用阻塞io,它可以处理情况3。但是,由于Thread.interrupt()调用,每次对Disconnect的调用都会引发异常。

import java.io.ByteArrayOutputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.LinkedBlockingQueue;

import java.util.Scanner; 

public class TCPClient {
private Socket                      client_socket_ = null;
private OutputWriterThread          output_writer_ = null;
private InputReaderThread           input_reader_  = null;
private LinkedBlockingQueue<String> send_queue_    = null;
private boolean                     connected_     = false;

public TCPClient()
{
    send_queue_ = new LinkedBlockingQueue<String>();
}

private class OutputWriterThread extends Thread
{
    @Override
    public void run()
    {    
        try (BufferedOutputStream data_out = new BufferedOutputStream(client_socket_.getOutputStream())){
            while (!Thread.currentThread().isInterrupted()) {
                if(send_queue_.size() > 0) {
                    data_out.write(send_queue_.poll().getBytes());
                    data_out.flush();
                }
            }
        } catch(IOException ex) {
            System.out.println("OutputWriterThread exception: " + ex.getMessage()); 
            Disconnect();
        } 
    }
}

private class InputReaderThread extends Thread
{
    @Override
    public void run()
    {
        try (BufferedInputStream data_in = new BufferedInputStream(client_socket_.getInputStream())) {
            ByteArrayOutputStream parser = new ByteArrayOutputStream(2048);
            byte[] buffer = new byte[2048];
            while (!Thread.currentThread().isInterrupted()) {   
                if(data_in.available() > 0) {
                    parser.write(buffer, 0, data_in.read(buffer));    
                    DataReceived(parser.toString("UTF-8")); 
                    parser.reset();
                }
            }
        } catch(IOException ex) {
            System.out.println("InputReaderThread exception: " + ex.getMessage()); 
            Disconnect();
        } 
    }
}

public synchronized void Connect(final String ip, final String port, final int timeout)
{
    System.out.println("connect attempted");
    if(!connected_) {
        try {
            System.out.println("starting connect function");
            client_socket_ = new Socket();
            client_socket_.connect(new InetSocketAddress(ip, Integer.parseInt(port)), timeout);

            output_writer_ = new OutputWriterThread();
            input_reader_  = new InputReaderThread();

            output_writer_.start();
            input_reader_.start();

            connected_ = true;
            System.out.println("ending connect function");
        } catch(IOException ex) {
            System.out.println("Connect:" + ex.getMessage());
        }
    }
}

public void SendData(final String data)
{
    try {
        if(connected_) send_queue_.offer(data);
    } catch(NullPointerException ex) {
        System.out.println("SendData:" + ex.getMessage()); 
    } 
}

public void DataReceived(String data)
{
    System.out.println(data); 
}

public boolean IsConnected()
{
    return connected_;
}

public synchronized void Disconnect()
{
    System.out.println("disconnect attempted");
    if(connected_) {
        try {
            System.out.println("starting disconnect function");
            output_writer_.interrupt();
            input_reader_.interrupt();

            System.out.println("Before closing the socket");
            client_socket_.close();
            connected_ = false;

            System.out.println("ending disconnect function");
        } catch(IOException ex) {
            System.out.println("Disconnected exception:" + ex.getMessage());
        } 
    }
}

public static void main(String[] args) { 
    Scanner sc = new Scanner(System.in);

    TCPClient client = new TCPClient();
    client.Connect("10.0.0.8", "9001", 5000);

    while(true) {
        String msg = sc.nextLine();

        if(msg.equals("exit"))
            break;

        client.SendData(msg);
    }

    client.Disconnect();
}
}

更具体地说,我想知道在不对服务器执行ping操作的情况下,是否有任何方法可以检查套接字是否损坏(如我上面指出的3种情况)。

更新:

我重新编写了代码,现在我可以轻松地检测到套接字损坏,并且解决了我之前无法检测到的3种情况。

当前问题

每当我从应用程序发送“退出”消息时,它都会调用Disconnect()方法(正确的行为)。但是,它会引发异常:“ InputReaderThread异常:套接字已关闭”(错误)。

我理解发生这种情况是因为我在Disconnect()方法中调用client_socket_.close(),并且因为inputStream.read(byte [] b)是一个阻塞方法(在InputReaderThread类内部),它检测到套接字已关闭并且抛出“套接字关闭”异常,因为无法从关闭的套接字读取。

我尝试了交换:

data_out_.close();
data_in_.close();

使用:

client_socket_.shutdownOutput();
client_socket_.shutdownInput();

即使Socket.shutdownInput()的功能描述为:

  

将此套接字的输入流放在“流的末尾”。任何数据   发送到套接字的输入流端的消息得到确认,然后   默默丢弃。如果您从套接字输入流读取后   在套接字上调用shutdownInput()时,流将返回EOF。

在shutdownInput()之后调用read(byte [] b)并没有实际返回EOF,我也通过在调用client_socket_.shutdownInput()之后在input_reader上调用join()对其进行了测试,结果程序停止了在while((bytes_read = data_in_.read(buffer))!= -1)行时,从未读取过EOF。

我缺少明显的东西吗?还是Java的正常行为?

新代码

import java.io.ByteArrayOutputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;

import java.util.Scanner; 

public class TCPClient {
    private Socket               client_socket_ = null;
    private BufferedOutputStream data_out_      = null;
    private BufferedInputStream  data_in_       = null;

    private boolean connected_ = false;

    private class InputReaderThread extends Thread
    {
        @Override
        public void run()
        {
            try {
                ByteArrayOutputStream parser = new ByteArrayOutputStream(2048);
                byte[] buffer = new byte[2048];
                int bytes_read;
                while ((bytes_read = data_in_.read(buffer)) != -1) {
                    parser.write(buffer, 0, bytes_read);    
                    DataReceived(parser.toString("UTF-8")); 
                    parser.reset();
                }
                Disconnect();
            } catch(IOException ex) {
                System.out.println("InputReaderThread exception: " + ex.getMessage()); 
            } 
        }
    }

    public synchronized void Connect(final String ip, final String port, final int timeout)
    {
        System.out.println("connect attempted");
        if(!connected_) {
            try {
                System.out.println("starting connect function");
                client_socket_ = new Socket();
                client_socket_.connect(new InetSocketAddress(ip, Integer.parseInt(port)), timeout);

                data_out_ = new BufferedOutputStream(client_socket_.getOutputStream());
                data_in_  = new BufferedInputStream(client_socket_.getInputStream());

                InputReaderThread input_reader = new InputReaderThread();
                input_reader.start();

                connected_ = true;
                System.out.println("ending connect function");
            } catch(IOException ex) {
                System.out.println("Connect:" + ex.getMessage());
            }
        }
    }

    public synchronized void SendData(final String data)
    {
        if(connected_)
        {
            Thread output_writer = new Thread() {
                @Override
                public void run()
                {    
                    try {                     
                        data_out_.write(data.getBytes());
                        data_out_.flush();                              
                    } catch(IOException ex) {
                        System.out.println("SendData exception: " + ex.getMessage()); 
                        Disconnect();
                    } 
                }
            };
            output_writer.start();
        }
    }

    public void DataReceived(String data)
    {
        System.out.println(data); 
    }

    public boolean IsConnected()
    {
        return connected_;
    }

    public synchronized void Disconnect()
    {
        System.out.println("disconnect attempted");
        if(connected_) {
            try {
                System.out.println("starting disconnect function");

                data_out_.close();
                data_in_.close();
                client_socket_.close();
                connected_ = false;

                System.out.println("ending disconnect function");
            } catch(IOException ex) {
                System.out.println("Disconnected exception:" + ex.getMessage());
            } 
        }
    }

    public static void main(String[] args) { 
        Scanner sc = new Scanner(System.in);

        TCPClient client = new TCPClient();
        client.Connect("10.0.0.6", "9001", 5000);

        while(true) {
            String msg = sc.nextLine();

            if(msg.equals("exit"))
                break;

            client.SendData(msg);
        }

        client.Disconnect();
    }
}

0 个答案:

没有答案