Java socket сервер + ESP-01 клиент
- Войдите на сайт для отправки комментариев
Комрады прошу помощи, при постороении умного дома наткнулся самую банальную проблемму, передачу информации. На малинке поднят сервер на яве вот с таким кодом
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. если посоветуете хорошую литературу для профанов и чайников, буду признателен весьма.
Как говориться, утро вечера мудренее.
Возможно я нашёл ответ.
https://stackoverflow.com/questions/43703021/sending-data-from-java-serv...