net-socket.io — это небольшая оболочка для библиотеки узлов, которая упрощает низкоуровневое программирование сокетов в JavaScript. Он в значительной степени основан на Socket.io и Event Emitters.

const { Server } = require('ipc-socket.io');
const io = Server('/tmp/socket');
io.on('connection', function(socket){
  socket.emit('message', {
    text: 'hello',
    totalClients: io.sockets
  }); 
});

Но почему?

Вариант использования для этой библиотеки такой же, как вариант использования для библиотеки узла. Который на самом деле имеет те же варианты использования, что и сокеты TCP или сокеты домена UNIX. Так что на самом деле все дело в розетках.

Примечание. Модуль net использует сокеты во всем, что не является Windows, и использует именованные каналы в Windows.

Розетки

Вы знаете, типа сокеты Беркли, а не веб-сокеты.

API сокетов, доступный практически на всех компьютерах, используется для межпроцессного взаимодействия (IPC). Таким образом, мы можем использовать сокеты для связи двух или более приложений друг с другом. Эти приложения могут находиться на одном хосте (компьютере) или на разных хостах (компьютерах). На самом деле мы можем создать HTTP-сервер и клиент с помощью сокетов. Но мы также могли бы просто создать TCP-сервер и клиент, используя сокеты, без накладных расходов, связанных с какими-либо другими протоколами, такими как HTTP.

Используя сокеты, мы могли бы создать серверное приложение TCP, которое разрешает соединения из клиентских приложений TCP. Как видите, это очень похоже на стандартный веб-сервер, использующий HTTP и WebSockets, но это просто старый TCP без каких-либо других протоколов.

Просто для справки: мы можем использовать сокеты для создания TCP-серверов и клиентов с 1983 года. HTTP был представлен в 1991 году, а протокол WebSockets — в 2011 году. Так что это *старый* способ ведения дел.

Пример использования net-socket.io

сервер:

const { Server } = require('ipc-socket.io');
const io = Server(3000);
io.on('connection', (socket) => {
  socket.on('message', (data) => {
    console.log('socket sent a message', data);
  })
});

клиент:

const { Socket } = require('ipc-socket.io');
const socket = Socket(3000, 'localhost');
socket.on('ready', () => {
  socket.emit('message', 'hello');
});

Примечание. Если вам действительно нужна двусторонняя связь между клиентом и сервером, подключенными к Интернету, веб-сокеты будут гораздо лучшим вариантом, чем обычные сокеты TCP.

Сокет домена Unix

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

Мы по-прежнему можем использовать сокеты, но они не должны взаимодействовать через TCP. Вместо этого все коммуникации могут происходить исключительно внутри ядра операционной системы. Сокеты делают это путем привязки к имени пути файловой системы.

Пример использования net-socket.io

сервер:

const { Server } = require('ipc-socket.io');
const io = Server('/tmp/my-app');
io.on('connection', (socket) => {
  socket.on('message', (data) => {
    console.log('socket sent a message', data);
  })
});

клиент:

const { Socket } = require('ipc-socket.io');
const socket = Socket('/tmp/my-app');
socket.on('ready', () => {
  socket.emit('message', 'hello');
});

И вуаля, у нас есть приложения на одной машине, которые могут взаимодействовать друг с другом в двух направлениях.

Но почему?

Зачем нам создавать несколько приложений на одном компьютере, которые взаимодействуют друг с другом? Если все приложения работают на одном компьютере, почему бы просто не создать одно большое приложение вместо нескольких более мелких?

Причин много-много, но для меня есть два основных мотиватора.

Языковая свобода

Обычно нам нужно использовать один и тот же язык для всего, когда мы пишем приложение. Если мы пишем приложение на JavaScript, мы можем использовать только JavaScript и библиотеки, написанные на JavaScript. Конечно, есть исключения, например, почти каждый язык имеет способ импорта C или C++ библиотек; но предположим, что мы создаем веб-приложение, которое позволяет пользователям загружать изображения для классификации по модели ML. Мы могли бы построить сервер HTTP в JavaScript, но создать функцию классификации изображений в Python. Используя сокеты, мы могли бы создавать несколько приложений на нескольких языках, каждое из которых представляет одну функцию, работающую на одном компьютере и взаимодействующую друг с другом для формирования единого приложения.

Конечно, библиотека net-socket.io существует только как библиотека JavaScript. Это означает, что приложению, написанному на другом языке, потребуется собственная библиотека net-socket.io. Или пришлось бы использовать встроенный в язык способ использования сокетов. Вот список API сокетов по умолчанию для некоторых популярных языков:

  • Питон
  • "Рубин"
  • Го Ланг
  • РНР
  • C#
  • Некоторые языки, такие как Java и Swift, должны полагаться на библиотеку системных сокетов по умолчанию #include <sys/socket.h>

Модульность

Поговорим немного об архитектуре приложения. Когда мы пишем программное обеспечение, мы обычно хотим, чтобы наш код был модульным. Мы хотим, чтобы различные части нашего приложения были независимыми друг от друга, что сделало их более стабильными и многоразовый.

Пример:

Плохо:

const numbers = [1, 2, 3];
function sumNumbers() {
  const result = numbers.reduce((n, a) => n+a);
  console.log(result);
}

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

Хорошо:

function sumNumbers(numbers) {
  const result = numbers.reduce((n, a) => n+a);
  return result;
}
const numbers = [1, 2, 3];
const result = sumNumbers(numbers);
console.log(result);

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

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

Модульность с использованием библиотек

Отличный способ обеспечить модульность и независимость — создать библиотеки для разных частей нашего кода. Если мы возьмем любую часть нашего приложения, которую можно превратить в библиотеку, и превратим ее в библиотеку, мы получим очень модульный код.

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

Пример:

Библиотека суммирующих чисел:

function sumNumbers(numbers) {
  const result = numbers.reduce((n, a) => n+a);
  return result;
}
module.exports = sumNumbers;

У этой библиотеки нет возможности узнать об остальной части нашего приложения.

Мое приложение:

npm install summmmmm-numbers
const sumNumbers = require('summmmmm-numbers');
const numbers = [1, 2, 3];
const result = sumNumbers(numbers);
console.log(result);

Мне нравится создавать приложение, создавая универсальные библиотеки. Единственное, что я люблю больше, — это создавать приложение из небольших приложений.

Модульность с использованием приложений

Теперь представьте, что вместо того, чтобы разделить наш код на разные библиотеки, мы разделили его на разные приложения.

Пример:

Приложение Sum Numbers:

const io = require('ipc-socket.io').Server('/tmp/sum_numbers');
function sumNumbers(numbers) {
  const result = numbers.reduce((n, a) => n+a);
  return result;
}
io.on('connection', socket => {
  socket.on('sum', numbers => {
    socket.emit('result', sumNumbers(numbers));
  });
});

Мое приложение:

const socket = require('ipc-socket.io').Socket('/tmp/sum_numbers');
socket.on('result', result => {
  console.log(result);
});
socket.on('ready', () => {
  socket.emit('sum', [1,2,3,4,5,6]);
});

Это не может быть намного более модульным, чем это. Мой код разделен на совершенно отдельные приложения. Это также приводит к более чистому управлению приложениями. Каждый раз, когда я развертываю обновление, мне нужно обновить только приложение, в котором произошло изменение. Все остальное может оставаться нетронутым.

Резюме

Мы можем использовать сокеты для обеспечения связи между двумя или более приложениями. Эти приложения могут быть на одном компьютере или на разных компьютерах. Это позволяет нам использовать больше языков и писать приложения разными способами, что может сделать наш код более модульным.

Для начала ознакомьтесь с библиотекой net-socket.io.

Первоначально опубликовано на https://sammeechward.com 16 июля 2019 г.