2016-05-31

Взаимодействие Android-приложения и сервера на Node.js

При работе над одним из проектов понадобилось разбираться с взаимодействием клиентского Android-приложения и сервера на Node.js.


Сокеты, потоки и буферы

В Java для работы с данными, помимо обычных массивов, применяются буферы ByteBuffer и подобные. ByteBuffer принципиально отличается от массива тем, что не имеет свойства хранящего размер. а оперирует такими понятиями как position, limit, capacity и mark.
В Node.js есть похожий, широко используемый, класс Buffer.
Документация по ByteBuffer.
Документация по Buffer.

Для соединения через сокеты в Java используются классы Socket, SocketChannel и потоки. SocketChannel при чтении/записи оперирует ByteBuffer. Потоки чтения/записи (InputStream/OutputStream) могут работать как с массивами байт, так и массивами символов, в зависимости от используемого класса обработчика потока.

Клиент Android/Java

Подключение к сокету и извлечение входного и выходного потоков:
Socket mSocket.connect(new InetSocketAddress(mIP, mPort));
BufferedReader br = new BufferedReader(new InputStreamReader(mSocket.getInputStream()));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(mSocket.getOutputStream()));

Для чтения строк из потока удобно использовать BufferReader, его метод readLine возвращает строку или null, если нет данных. Аналогично, для отправки строк в поток, используется BufferedWriter с методами write и flush.

Сервер Node.js

let server = net.createServer((socket) => {
 // обработчик, вызывающийся при подключении клиента к сокету

 setTimeout(() => {
  // отправка текста через сокет
  socket.write('test hello\n')
  // отправка FIN-пакета
  socket.end()
 }, 3000)

 socket.on('data', (buffer) => {
  // событие получения очередного буфера с данными через сокет
  console.log(buffer)
 })

 socket.on('end', () => {
  // обработчик, вызывающийся при отключении клиента от сокета
 })

 // вот так просто можно направить весь поток данных из сокета напрямую в файл
 let file_stream = fs.createWriteStream('socket.txt')
 socket.pipe(file_stream)
})

// указываем порт и адрес, на которых сокет-сервер будет ожидать подключения
server.listen(port, host_address, () => {
 address = server.address()
 console.log('server: %j', address)
})

Демо

Демонстрация простого взаимодействия
android-node-demo