Я создаю клиентское приложение для сокетов, которое подключается к ESP8266-01, и единственное, что я не могу понять - как обнаружить сломанный сокет без проверки связи с сервером (ESP8266-01).
До сих пор я обнаружил 3 случая, когда я считаю, что сокет сломан, потому что клиентское приложение не может их обнаружить:
1) Резкое отключение ESP8266 от источника питания без надлежащего закрытия сокета
2) Отключение Wi-Fi, к которому подключено и мое приложение, и ESP8266.
3) Вызов AT + CIPCLOSE из ESP8266.
Если произойдет что-либо из вышеперечисленного, и я отправлю данные с помощью SendData() будет сгенерировано и обработано исключение, за исключением случая 1., в котором оно просто остается незамеченным.Я пытался использовать блокировку io раньше, и она учитывает случай 3. Однако каждый вызов Disconnect будет вызывать исключение из-за вызовов Thread.interrupt ().
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();
}
}
Чтобы быть более конкретным, я хочучтобы узнать, есть ли способ проверить, не сломан ли сокет (как 3 случая, которые я указал выше), не пропингуя сервер.
ОБНОВЛЕНИЕ:
Я повторнонаписал код, и теперь я могу легко обнаружить сломанный сокет, и 3 случая, которые я не смог обнаружить ранее, решены.
ТЕКУЩАЯ ПРОБЛЕМА
Всякий раз, когда я посылаю "выход"из приложения вызывается метод Disconnect () (правильное поведение).Однако это вызывает исключение: «InputReaderThread exception: Socket closed» (ОШИБКА).
Я понимаю, что это происходит потому, что я вызываю client_socket_.close () в методе Disconnect () и потому что inputStream.read(byte [] b) является методом блокировки (внутри класса InputReaderThread), он обнаруживает, что сокет был закрыт, и выдает исключение «Socket closed», потому что чтение из закрытого сокета невозможно.
Я попытался обменяться:
data_out_.close();
data_in_.close();
С:
client_socket_.shutdownOutput();
client_socket_.shutdownInput();
И даже если описание функции Socket.shutdownInput () равно:
Помещает входной поток для этогосокет в "конце потока".Любые данные, отправленные на сторону входного потока сокета, подтверждаются, а затем молча отбрасываются.Если вы читаете из входного потока сокета после вызова shutdownInput () для сокета, поток вернет EOF.
Вызов read (byte [] b) после shutdownInput () фактически не возвращает EOFкогда это было необходимо, и я также проверил это, вызвав метод join () для input_reader после вызова client_socket_.shutdownInput (), и в результате программа остановилась на строке while ((bytes_read = data_in_.read (buffer))! = -1) и noEOF когда-либо читали.
Я что-то упускаю из виду?или это просто нормальное поведение для Java?
NEW CODE
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();
}
}