logo
+7 (495) 997-37-74
Москва, ул.Международная, 15

Сетевые возможности Processing

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

В этой статье мы рассмотрим базовые примеры сетевого взаимодействия как скетчей на Processing, так и взаимодействие Processing с удалёнными ресурсами (в нашем случае с веб-сайтом в интернете).

Типы сетевых взаимодействий Processing

Как мы уже отметили, Processing имеет развитые сетевые возможности и позволяет осуществлять различные сценарии сетевого взаимодействия. Перечислим основные сетевые возможности Processing:

  • Работа в качестве клиента и подключение к другим системам на Processing
  • Работа в качестве веб-сервера и обслуживание внешних подключений
  • Получение данных и команд от контроллеров в локальной сети
  • Создание визуальных интерфейсов и сетевое управление подключённым оборудованием
  • Визуализация получаемых по сети данных
  • Обмен данными с веб-сайтами в интернете
  • Сниффинг и визуализация сетевой активности
  • и множество других сетевых возможностей...

Как вы видите, тема сетевых возможностей Processing чрезвычайно широка (и очень интересна) и раскрыть её в одной статье просто невозможно, поэтому в этой статье мы уделим внимание клиент-серверному взаимодействию и получению данных с интернет-сайтов, а остальные, не менее интересные варианты сетевой работы Processing, мы разберём в других статьях.

Клиент-серверное взаимодействие

Клиент-серверное взаимодействие мы разберём на примере построения системы распределённой совместной работы по редактированию графики. Несмотря на то, что сама формулировка задачи выглядит очень сложной и неприступной, далее мы увидим, что она довольно просто решается средствами Processing (знаменитая магия Processing).

Итак, сначала нам нужно создать скетч сервера, который будет выполнять две основные функции: позволит нам в графическом окне рисовать курсором мыши и будет работать собственно сервером, позволяя клиентам по сети подключаться к себе. А поскольку наш сервер специализированный, то он позволит отображать данные клиентов (их движения мышью) на нашем холсте (графическом окне). То есть мы будем одновременно видеть свои действия по редактированию графики (белым цветом) и действия клиента (чёрным цветом) и у нас с клиентом будет два одинаковых (удалённо синхронизируемых) графических окна.

Теперь полный код скетча сервера:

/*
  Network Draw (Server)
*/

import processing.net.*;

Server sv; 
Client cl;

void setup() { 
  size(300, 200);
  background(200);
  frameRate(5);
  
  sv = new Server(this, 12321);
}

void draw() { 
  if (mousePressed == true) {
    stroke(255);
    line(pmouseX, pmouseY, mouseX, mouseY); 
    
    sv.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
  }
  
  cl = sv.available();
  if (cl != null) {
    String input = cl.readString(); 
    input = input.substring(0, input.indexOf("\n"));
    int data[] = int(split(input, ' '));

    stroke(0);
    line(data[0], data[1], data[2], data[3]); 
  }
}

Сразу бросается в глаза простота реализации такой сложной задачи. Теперь рассмотрим поподробнее работу скетча сервера.

Сначала мы подключаем необходимую сетевую библиотеку.

import processing.net.*;

Затем объявляем объекты сервера и клиента

Server sv; 
Client cl;

Задаём размер графического окна, цвет фона, и устанавливаем частоту обновления экрана 5 раз в секунду (для того, чтобы система успевала обмениваться данными по сети).

  size(300, 200);
  background(200);
  frameRate(5);

И запускаем сервер на 12321 порту (порт может быть другим, по вашему желанию, только нужно помнить, что и в скетче клиента он должен быть таким же).

  sv = new Server(this, 12321);

Далее в циклической функции draw() мы проверяем нажатие кнопки мыши и в случае нажатия устанавливаем белый цвет и проводим линию в текущие координаты указателя мыши (рисуем линии белым цветом в своём графическом окне).

void draw() { 
  if (mousePressed == true) {
    stroke(255);
    line(pmouseX, pmouseY, mouseX, mouseY); 
    
    sv.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
  }

Одновременно отсылаем наши актуальные координаты миши клиенту, разделяя их пробелами.

    sv.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");

Далее проверяем наличие данных от клиента.

  cl = sv.available();
  if (cl != null) {

И если данные присутствуют, то читаем их и обрезаем до символа «\n».

    String input = cl.readString(); 
    input = input.substring(0, input.indexOf("\n"));

Затем парсим пришедшие данные и заполняем ими массив data.

    int data[] = int(split(input, ' '));

Далее устанавливаем чёрный цвет и отрисовываем «клиентскую» линию в нашем графическом окне.

    stroke(0);
    line(data[0], data[1], data[2], data[3]); 

Вот, собственно, и весь код «графического» сервера, теперь переходим к созданию скетча клиента.

Исходя из функционала, описанного в постановке задачи, понятно, что код клиента должен быть очень похож на код сервера, поскольку они выполняют практически одни и те же функции. Вот код клиента:

/*
  Network Draw (Client)
*/

import processing.net.*; 

Client cl; 

void setup() { 
  size(300, 200); 
  background(200);
  frameRate(5);
  
  cl = new Client(this, "127.0.0.1", 12321);
} 

void draw() {         
  if (mousePressed == true) {
    stroke(255);
    line(pmouseX, pmouseY, mouseX, mouseY); 
    
    cl.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
  }

  if (cl.available() > 0) { 
    String input = cl.readString(); 
    input = input.substring(0, input.indexOf("\n"));
    int data[] = int(split(input, ' '));
    
    stroke(0);
    line(data[0], data[1], data[2], data[3]); 
  } 
}

Остановимся на отличии этих двух скетчей. Здесь в функции setup() вместо сервера мы запускаем клиент. Обратите внимание, что клиент должен работать на том же порту, что и сервер (в нашем случае 12321). Поскольку и клиент и сервер запущены на одном компьютере, то в качестве IP адреса указан локальный 127.0.0.1.

  cl = new Client(this, "127.0.0.1", 12321);

Далее идёт функция draw(), практически аналогичная вышерассмотренной.

void draw() {         
  if (mousePressed == true) {
    stroke(255);
    line(pmouseX, pmouseY, mouseX, mouseY); 
    
    cl.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");
  }

  if (cl.available() > 0) { 
    String input = cl.readString(); 
    input = input.substring(0, input.indexOf("\n"));
    int data[] = int(split(input, ' '));
    
    stroke(0);
    line(data[0], data[1], data[2], data[3]); 
  } 
}

За исключением строки клиента, а не сервера, как в предыдущем случае.

    cl.write(pmouseX + " " + pmouseY + " " + mouseX + " " + mouseY + "\n");

В результате мы видим следующую картину на сервере:

Где светлая линия в графическом окне сервера проведена именно на сервере, а чёрный треугольник нарисован мышкой в графическом окне клиента. Теперь скриншот графического окна клиента:

Как вы видите, это полностью совпадающая картина, только выполненная противоположными цветами (что мы и ожидали увидеть).

Получение данных с сайта

Теперь давайте рассмотрим ещё один тип сетевого взаимодействия, поддерживаемый Processing. В данном случае речь пойдёт о функции loadStrings(), которая может загружать информацию из файлов или... из ресурса (сайта) по указанному URL адресу!

Другими словами, вы можете указать этой функции GET запрос — и она вернёт вам ответ сервера в качестве массива строк. Это поистине «волшебная» функция, которой пытливый исследователь сможет найти множество интересных и полезных применений.

Давайте попробуем на практических примерах познакомиться с loadStrings() поближе. Начнём с самого простого примера:

/*
  Get Site
*/

void setup() {
  String[] site = loadStrings("http://elabory.ru");
  println(site);
}

Вроде всего две строчки кода, но каков эффект:

Processing скачал из интернета страницу сайта и вывел её HTML код в консоль. Таким образом можно закачивать страницы или делать GET запросы и получать ответы, доступные для дальнейшего анализа и обработки.

Примечание. Единственным недостатком функции loadStrings() является её работа по незащищённому протоколу HTTP. Но даже в этом варианте ей можно найти множество полезных применений, например получение данных с контроллеров по локальной сети.

Теперь давайте расширим функционал нашего скетча и добавим в него функцию сохранения скачанных данных в файл. Код модернизированного скетча:

/*
  Get Site 2
*/

void setup() {
  PrintWriter file = createWriter("data/site.txt");
  
  String[] site = loadStrings("http://elabory.ru");
  println(site);
  
  for (int i = 0; i < site.length; i++) {
    file.println(site[i]);
  }
  
  file.flush();
  file.close();
}

Здесь мы создаём файл site.txt.

PrintWriter file = createWriter("data/site.txt");

И построчно записываем в него содержимое скачанной страницы. Вот результат работы нашего модернизированного скетча, открываем файл site.txt в блокноте на компьютере:

Теперь давайте попробуем осуществить обработку скачанных данных средствами Processing. В качестве примера мы выделим из скачанного кода тело страницы (начало и конец тега body) и добавим на это место нашу метку. Код нового скетча:

/*
  Get Site 3
*/

void setup() {
  PrintWriter file = createWriter("data/site.txt");
  
  String[] site = loadStrings("http://elabory.ru");
  println(site);

  for (int i = 0; i < site.length; i++) {
    file.print(site[i]);
    
    if (site[i].indexOf("") != -1) {
      file.println(" BODY START!");
      file.print("...parse content...");
    }
    
    if (site[i].indexOf("") != -1) {
      file.print(" BODY END!");
    }
    file.println();
  }
  
  file.flush();
  file.close();
}

Здесь мы определяем начало тега body и добавляем соответствующие надписи.

    if (site[i].indexOf("") != -1) {
      file.println(" BODY START!");
      file.print("...parse content...");
    }

И конец тега body.

    if (site[i].indexOf("") != -1) {
      file.print(" BODY END!");
    }

Вот результат нашего анализа скачанных данных, записанный в файл на диске нашего компьютера:

Таким образом можно организовать получение информации со страниц веб-сайтов и локальных контроллеров, а также получать информацию посредством GET запросов к различным системам и, далее, осуществлять анализ и обработку полученных данных.

Заключение

В этой статье мы рассмотрели два варианта сетевой работы Processing, за кадром остались ещё множество не менее интересных возможностей наподобие организации веб-сервера, FTP клиента, сетевого сниффера и т. п. С этими примерами использования сетевых возможностей Processing мы познакомим вас в других наших статьях.

Ссылки по теме

Система программирования Processing

Processing и Ардуино. Работа по Serial

Сетевые возможности Processing

Работа Processing в браузере и на сайте