Java socket сервер + ESP-01 клиент

spindle
Offline
Зарегистрирован: 21.02.2019

Комрады прошу помощи, при постороении умного дома наткнулся самую банальную проблемму, передачу информации. На малинке поднят сервер на яве вот с таким кодом

import java.net.ServerSocket;
import java.net.Socket;
import java.io.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
 /** * Класс сервера. Сидит тихо на порту, принимает сообщение, создает SocketProcessor на каждое сообщение */
 public class ChatServer {    
	private ServerSocket ss; 			// сам сервер-сокет   
	private Thread serverThread; 		// главная нить обработки сервер-сокета 
	private int port; 					// порт сервер сокета.    
	//очередь, где храняться все SocketProcessorы для рассылки    
	BlockingQueue<SocketProcessor> q = new LinkedBlockingQueue<SocketProcessor>();     
 /**   
 * Конструктор объекта сервера     
 * @param port Порт, где будем слушать входящие сообщения.     
 * @throws IOException Если не удасться создать сервер-сокет, вылетит по эксепшену, объект Сервера не будет создан    
 */ 
 
 public ChatServer(int port) throws IOException {       
	ss = new ServerSocket(port); // создаем сервер-сокет        
	this.port = port; // сохраняем порт.    
}     
 /**     
 * главный цикл прослушивания/ожидания коннекта.    
 */
 void run() { 
	serverThread = Thread.currentThread(); // со старта сохраняем нить (чтобы можно ее было interrupt())  
	while (true) { //бесконечный цикл, типа...            
	Socket s = getNewConn(); // получить новое соединение или фейк-соедиение           
		if (serverThread.isInterrupted()) { // если это фейк-соединение, то наша нить была interrupted(),             
				// надо прерваться                
			break;           
		} else if (s != null){ // "только если коннект успешно создан"...           
			try {                   
				final SocketProcessor processor = new SocketProcessor(s); // создаем сокет-процессор                
				final Thread thread = new Thread(processor); // создаем отдельную асинхронную нить чтения из сокета              
				thread.setDaemon(true); //ставим ее в демона (чтобы не ожидать ее закрытия)         
				thread.start(); //запускаем                
				q.offer(processor); //добавляем в список активных сокет-процессоров      
			} //тут прикол в замысле. Если попытка создать (new SocketProcessor()) безуспешна,    
				// то остальные строки обойдем, нить запускать не будем, в список не сохраним         
			catch (IOException ignored) {}  // само же исключение создания коннекта нам не интересно.      
		}      
	}   
 } 
 
 /**    
 * Ожидает новое подключение.     
 * @return Сокет нового подключения  
 */  
 
 private Socket getNewConn() {       
	Socket s = null;      
	try {         
		s = ss.accept();    //метод библиотеки
	} catch (IOException e) {     
		shutdownServer(); // если ошибка в момент приема - "гасим" сервер     
	}       
	return s;   
 }    
 
 /**  
 * метод "глушения" сервера   
 */ 
 
 private synchronized void shutdownServer() {        // обрабатываем список рабочих коннектов, закрываем каждый    
	for (SocketProcessor s: q) {       
		s.close();     
	}      
	if (!ss.isClosed()) {     
		try {         
			ss.close();   
		} catch (IOException ignored) {}    
	}  
 } 
 
 /**   
 * входная точка программы   
 * @param args   
 * @throws IOException  
 */  
 
 public static void main(String[] args) throws IOException { 
	new ChatServer(45000).run(); // если сервер не создался, программа    
								 // вылетит по эксепшену, и метод run() не запуститься   
 }  
 
 /**   *****************************************************************
 * вложенный класс асинхронной обработки одного коннекта.   
 */  
 
 private class SocketProcessor implements Runnable{  
	Socket s; // наш сокет     
	BufferedReader br; // буферизировнный читатель сокета    
	BufferedWriter bw; // буферизированный писатель в сокет   
 /**     
 * Сохраняем сокет, пробуем создать читателя и писателя. Если не получается - вылетаем без создания объекта   
 * @param socketParam сокет      
 * @throws IOException Если ошибка в создании br || bw    
 */    
 
	SocketProcessor(Socket socketParam) throws IOException {    
		s = socketParam;      
		br = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));    
		bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream(), "UTF-8") );  
	}      
 /**    
 * Главный цикл чтения сообщений/рассылки    
 */     
 public void run() {     
	while (!s.isClosed()) { // пока сокет не закрыт...      
	String line = null;          
		try {           
			line = br.readLine(); // пробуем прочесть.      
		} catch (IOException e) {   
			close(); // если не получилось - закрываем сокет.      
		}          
	if (line == null) { // если строка null - клиент отключился в штатном режиме.       
		close(); // то закрываем сокет     
	} else if ("shutdown".equals(line)) { // если поступила команда "погасить сервер", то... 
		serverThread.interrupt(); // сначала возводим флаг у северной нити о необходимости прерваться.    
	try {                  
		new Socket("localhost", port); // создаем фейк-коннект (чтобы выйти из .accept())    
	} catch (IOException ignored) { //ошибки неинтересны   
	} finally {           
		shutdownServer(); // а затем глушим сервер вызовом его метода shutdownServer().        
	}           
		} else { // иначе - банальная рассылка по списку сокет-процессоров        
		for (SocketProcessor sp:q) {       
		sp.send(line);           
		}            
		}         
	}     
 }     
 /**   
 * Метод посылает в сокет полученную строку       
 * @param line строка на отсылку    
 */      
 public synchronized void send(String line) {       
	try {     
		bw.write(line); // пишем строку   
		bw.write("\n"); // пишем перевод строки      
		bw.flush(); // отправляем      
	} catch (IOException e) {      
		close(); //если глюк в момент отправки - закрываем данный сокет. 
	}     
 }   
 /** 
 * метод аккуратно закрывает сокет и убирает его со списка активных сокетов     
 */    
 public synchronized void close() {    
	q.remove(this); //убираем из списка  
		if (!s.isClosed()) {           
		try {                 
			s.close(); // закрываем      
		} catch (IOException ignored) {}   
	}       
 }       
 /**     
 * финализатор просто на всякий случай.    
 * @throws Throwable       
 */     
 @Override    
 protected void finalize() throws Throwable {  
	super.finalize();     
	close();       
 }  
 }
 } 
 

Для него есть вот такой Java Клиент вместе они отлично работают.

import java.net.Socket;
import java.io.*; 
/** 
* Класс-клиент чат-сервера. Работает в консоли. Командой с консоли shutdown посылаем сервер в оффлайн 
*/
public class ChatClient {   
 final Socket s;  // это будет сокет для сервера  
 final BufferedReader socketReader; // буферизированный читатель с сервера  
 final BufferedWriter socketWriter; // буферизированный писатель на сервер   
 final BufferedReader userInput; // буферизированный читатель пользовательского ввода с консоли  
 /**  
 * Конструктор объекта клиента  
 * @param host - IP адрес или localhost или доменное имя   
 * @param port - порт, на котором висит сервер   
 * @throws java.io.IOException - если не смогли приконнектиться, кидается исключение, чтобы   
 * предотвратить создание объекта   
 */ 
 public ChatClient(String host, int port) throws IOException {   
	s = new Socket(host, port); // создаем сокет       
	// создаем читателя и писателя в сокет с дефолной кодировкой UTF-8    
	socketReader = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));   
	socketWriter = new BufferedWriter(new OutputStreamWriter(s.getOutputStream(), "UTF-8"));   
	// создаем читателя с консоли (от пользователя)      
	userInput = new BufferedReader(new InputStreamReader(System.in));    
	new Thread(new Receiver()).start();// создаем и запускаем нить асинхронного чтения из сокета   
 }    
 /**
 * метод, где происходит главный цикл чтения сообщений с консоли и отправки на сервер   
 */  
 public void run() {    
	System.out.println("Type phrase(s) (hit Enter to exit):");    
		while (true) {     
			String userString = null;    
			try {            
				userString = userInput.readLine(); // читаем строку от пользователя    
			} catch (IOException ignored) {} // с консоли эксепшена не может быть в принципе, игнорируем   
			//если что-то не так или пользователь просто нажал Enter...    
			if (userString == null || userString.length() == 0 || s.isClosed()) {   
				close(); // ...закрываем коннект.      
				break; // до этого break мы не дойдем, но стоит он, чтобы компилятор не ругался      
			} else { //...иначе...    
			try {             
				socketWriter.write(userString); //пишем строку пользователя          
				socketWriter.write("\n"); //добавляем "новою строку", дабы readLine() сервера сработал  
				socketWriter.flush(); // отправляем        
			} catch (IOException e) {                
				close(); // в любой ошибке - закрываем.     
			}      
		}      
	}   
 }   
 /** 
 * метод закрывает коннект и выходит из   
 * программы (это единственный  выход прервать работу BufferedReader.readLine(), на ожидании пользователя)   
 */   
 public synchronized void close() {//метод синхронизирован, чтобы исключить двойное закрытие.   
	if (!s.isClosed()) { // проверяем, что сокет не закрыт...        
	try {             
		s.close(); // закрываем...    
		System.exit(0); // выходим!    
	} catch (IOException ignored) {     
		ignored.printStackTrace();         
	}     
	}  
 }  
 
 public static void main(String[] args)  { // входная точка программы  
	try {     
		new ChatClient("localhost", 45000).run(); // Пробуем приконнетиться...  
		} catch (IOException e) { // если объект не создан...          
	System.out.println("Unable to connect. Server not running?"); // сообщаем...  
	} 
 }
 
 /**  *******************************************************************************
 * Вложенный приватный класс асинхронного чтения    
 */  
 
 //основной класс только отправляет сообщения на сервер а этот постоянно принимет.
 private class Receiver implements Runnable{   
 /** 
 * run() вызовется после запуска нити из конструктора клиента чата. 
 */       
 
 public void run() {     
	while (!s.isClosed()) { //сходу проверяем коннект.       
		String line = null; //читает то что прислал сервер.            
		try {                   
			line = socketReader.readLine(); // пробуем прочесть    
		} catch (IOException e) { // если в момент чтения ошибка, то...    
		// проверим, что это не банальное штатное закрытие сокета сервером      
			if ("Socket closed".equals(e.getMessage())) {                    
				break;                
		}          
		System.out.println("Connection lost"); // а сюда мы попадем в случае ошибок сети.  
			close(); // ну и закрываем сокет (кстати, вызвается метод класса ChatClient, есть доступ)   
		}            
			if (line == null) {  // строка будет null если сервер прикрыл коннект по своей инициативе, сеть работает  
				System.out.println("Server has closed connection");    
				close(); // ...закрываемся    
			} else { // иначе печатаем то, что прислал сервер.       
				System.out.println("Server:" + line);       
			}       
	}   
	}  
 }
 } 

Но как заставить ESP - 01 обмениваться инфой? 

На ESP нашёл вот такой вот код, но он только конектится, выкидывает на сервер отладочную информациб, и дисконектит каждые 2 минуты. 

#include <Arduino.h>

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>

#include <SocketIoClient.h>

#define USE_SERIAL Serial

ESP8266WiFiMulti WiFiMulti;
SocketIoClient webSocket;
WebSocketsClient WebClient;

void event(const char * payload, size_t length) {
  //USE_SERIAL.printf("got message: %s\n", payload);
}



void setup() {
    USE_SERIAL.begin(9600);

    //USE_SERIAL.setDebugOutput(true);

    USE_SERIAL.println();
    USE_SERIAL.println();
    USE_SERIAL.println();

      for(uint8_t t = 4; t > 0; t--) {
          USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\n", t);
          USE_SERIAL.flush();
          delay(1000);
      }

    WiFiMulti.addAP("11111","111111");

    while(WiFiMulti.run() != WL_CONNECTED) {
        delay(100);
    }

    webSocket.on("event", event);
   webSocket.begin("192.168.1.71",45000);
    WebClient.begin("192.168.1.71",45000);
    // use HTTP Basic Authorization this is optional remove if not needed
    //webSocket.setAuthorization("username", "password");
   // WebClient.onEvent(webSocketEvent);
   
}

void loop() {
    webSocket.loop();
     USE_SERIAL.println("111") ;
      //webSocket.emit("chat_message", "Arduino here, hello!");
      USE_SERIAL.flush();
      WebClient.sendTXT("111111111111111111") ;
    // webSocket.print("1111") ;
    delay(10000) ;
}

Мучаюсь третий день, нервные клетки на грани истощения. 

Вопросов собственно 3

1) как научить ESP Общаться с сервером?

2) почму сервер каждые 2 минуты дисконектит

3) как зотфильтровать отладочную информацию после коннекта

p.s. если посоветуете хорошую литературу для профанов и чайников, буду признателен весьма.

spindle
Offline
Зарегистрирован: 21.02.2019

Как говориться, утро вечера мудренее.
Возможно я нашёл ответ.
https://stackoverflow.com/questions/43703021/sending-data-from-java-serv...