В предыдущей статье «Транслируем звук по сети с помощью Java» я описывал способ приема и трансляции звука по сети встроенными средствами Java.
Здесь я продолжу развивать эту идею, и расскажу, как сделать с помощью Java простую систему IP-телефонии.
Система IP-телефонии состоит из серверной части, которая хранит учетные данные пользователей и их текущие IP, и консольного клиента, который способен совершать и принимать звонки напрямую от второго абонента.
Полностью исходники можно посмотреть на github.
Всех заинтересовавшихся прошу под кат.
Серверная часть работает на базе сервлетов, Apache Tomcat и MySQL.
База данных состоит из двух таблиц: users — хранит учетные данные пользователей и userinfo — сопоставляет каждому пользователю IP и время его последнего обновления.
Названия email и password говорят сами за себя, confirm — токен подтверждения почтового адреса либо 'done', если e-mail подтвержден, user_id — md5-хэш от адреса электронной почты (так как он имеет фиксированную длину, его удобно использовать для идентификации входящего звонка).
Поля email и user_id соответствуют полям из предыдущей таблицы, что такое ip понятно из названия, last_update — время последнего обновления IP.
RegisterServlet регистрирует пользователя в базе данных и высылает на электронную почту запрос на подтверждение с помощью следующего скрипта:
ConfirmServlet — выполняет подтверждение e-mail.
UpdateIPServlet — обновляет IP клиента при запросе, IP определяется автоматически.
GetUserInfoServlet — в качестве параметра принимает email или user_id, при запросе возвращает email или user_id и текущий IP, либо значение 'offline', если IP не обновлялся более трех минут.
Для установки серверной части нужно:
Консольный клиент состоит из четырех классов с программной логикой — Main, Master, Slave и IPUpdater, и двух вспомогательных классов — Util и DeclinedException.
Класс Util хранит настройки клиента — такие как параметры звука и объем буфера.
Класс Main отвечает за программную логику интерфейса.
Класс IPUpdater каждые 90 секунд отправляет сервлету запрос на обновление IP.
Класс Master слушает сетевой порт и, в свою очередь, содержит в себе два вложенных класса-потока: MicrophoneReader — читает данные с микрофона и Sender — отправляет данные второму абоненту.
Класс Slave: инициирует соединение, отправляя второму абоненту md5-хэш адреса электронной почты, затем, если звонок принят, начинает читать данные из сокета и отправлять их на аудио-выход.
Более подробно описывать устройство клиента, пожалуй, не стану — все желающие могут сами ознакомиться с исходным кодом.
Здесь можно взять готовый исполняемый jar.
Запуск:
Желающие могут попробовать на моем сервере:
Но: в целях хабраэффектоустойчивости сервера я установил ограничение в 100 зарегистрированных пользователей.
И последнее: если Вы сидите за роутером, нужно сделать редирект порта 7373 на свою машину.
Возникла небольшая проблема — когда я пытаюсь обновлять свой собственный IP через внешний хост, сервлет вместо моего внешнего IP получает IP моего роутера во внутренней сети — 192.168.1.1.
Придумал небольшой костыль — триггер для MySQL:
Здесь я продолжу развивать эту идею, и расскажу, как сделать с помощью Java простую систему IP-телефонии.
Система IP-телефонии состоит из серверной части, которая хранит учетные данные пользователей и их текущие IP, и консольного клиента, который способен совершать и принимать звонки напрямую от второго абонента.
Полностью исходники можно посмотреть на github.
Всех заинтересовавшихся прошу под кат.
NetworkingAudioServer — серверная часть системы
Серверная часть работает на базе сервлетов, Apache Tomcat и MySQL.
Структура базы данных
База данных состоит из двух таблиц: users — хранит учетные данные пользователей и userinfo — сопоставляет каждому пользователю IP и время его последнего обновления.
CREATE TABLE IF NOT EXISTS `users` (
`email` varchar(100) NOT NULL PRIMARY KEY,
`password` varchar(100) NOT NULL,
`confirm` varchar(100) NOT NULL,
`user_id` varchar(100) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Названия email и password говорят сами за себя, confirm — токен подтверждения почтового адреса либо 'done', если e-mail подтвержден, user_id — md5-хэш от адреса электронной почты (так как он имеет фиксированную длину, его удобно использовать для идентификации входящего звонка).
CREATE TABLE IF NOT EXISTS `userinfo` (
`email` varchar(100) NOT NULL PRIMARY KEY,
`user_id` varchar(100) NOT NULL,
`ip` varchar(100) NOT NULL,
`last_update` TIMESTAMP NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
Поля email и user_id соответствуют полям из предыдущей таблицы, что такое ip понятно из названия, last_update — время последнего обновления IP.
Сервлеты
RegisterServlet регистрирует пользователя в базе данных и высылает на электронную почту запрос на подтверждение с помощью следующего скрипта:
#!/bin/sh
email=$1
confirm=$2
SERVER_URL="http://tabatsky.ru/networkingaudio";
TMP_FILE="/common_scripts/tmp/$confirm";
echo "To: $email" > $TMP_FILE;
echo "From: service@tabatsky.ru" >> $TMP_FILE;
echo "Subject: Networking Audio e-mail confirmation" >> $TMP_FILE;
echo >> $TMP_FILE;
echo "$SERVER_URL/confirm?confirm=$confirm" >> $TMP_FILE;
echo >> $TMP_FILE;
sendmail $email < $TMP_FILE
ConfirmServlet — выполняет подтверждение e-mail.
UpdateIPServlet — обновляет IP клиента при запросе, IP определяется автоматически.
GetUserInfoServlet — в качестве параметра принимает email или user_id, при запросе возвращает email или user_id и текущий IP, либо значение 'offline', если IP не обновлялся более трех минут.
Настройка серверной части
Для установки серверной части нужно:
- Создать базу данных MySQL
- Указать правильные значения логина, пароля и базы данных MySQL в классе MyDBConnect
- Собрать и задеплоить на Tomcat
- Указать правильное значение SERVER_URL в скрипте отправки почты, сам скрипт разместить по адресу /common_scripts/sendConfirm и установить права на выполнение
- Создать папку /common_scripts/tmp и установить права на запись
jNetworkingAudioClient — консольный клиент
Структура клиента
Консольный клиент состоит из четырех классов с программной логикой — Main, Master, Slave и IPUpdater, и двух вспомогательных классов — Util и DeclinedException.
Класс Util хранит настройки клиента — такие как параметры звука и объем буфера.
Класс Main отвечает за программную логику интерфейса.
Класс IPUpdater каждые 90 секунд отправляет сервлету запрос на обновление IP.
Класс Master слушает сетевой порт и, в свою очередь, содержит в себе два вложенных класса-потока: MicrophoneReader — читает данные с микрофона и Sender — отправляет данные второму абоненту.
Класс Slave: инициирует соединение, отправляя второму абоненту md5-хэш адреса электронной почты, затем, если звонок принят, начинает читать данные из сокета и отправлять их на аудио-выход.
Более подробно описывать устройство клиента, пожалуй, не стану — все желающие могут сами ознакомиться с исходным кодом.
Запуск клиента
Здесь можно взять готовый исполняемый jar.
Запуск:
java -jar jNetworkingAudioClient.jar http://serverUrl 2>log.txt
Желающие могут попробовать на моем сервере:
java -jar jNetworkingAudioClient.jar http://tabatsky.ru/networkingaudio/ 2>log.txt
Но: в целях хабраэффектоустойчивости сервера я установил ограничение в 100 зарегистрированных пользователей.
И последнее: если Вы сидите за роутером, нужно сделать редирект порта 7373 на свою машину.
UPD:
Возникла небольшая проблема — когда я пытаюсь обновлять свой собственный IP через внешний хост, сервлет вместо моего внешнего IP получает IP моего роутера во внутренней сети — 192.168.1.1.
Придумал небольшой костыль — триггер для MySQL:
CREATE TRIGGER `my_host_ip` BEFORE INSERT ON `userinfo`
FOR EACH ROW SET NEW.ip=IF(NEW.ip='192.168.1.1','tabatsky.ru',NEW.ip);