- Находки программиста
- среда, 6 ноября 2013 г.
- UDP в Android: как приложения ищут друг друга в сети?
- Стрим видео с Android устройства по UDP в JAVA приложение
- Инсталляция пакета VLCJ
- Надо разобраться
- Казалось бы победа?
- Android-er
- Wednesday, June 1, 2016
- Android Datagram/UDP Server example
- 5 comments:
- Основы программирования UDP-сокетов на Java
- Но почему именно UDP?
- Коммуникация UPD-сокетов в действии
- Построение серверного UDP-сокета
- Создание клиентского UDP-сокета
- Запуск программ: демонстрация работы сокетов
Находки программиста
Решения конкретных задач программирования. Java, Android, JavaScript, Flex и прочее. Настройка софта под Linux, методики разработки и просто размышления.
среда, 6 ноября 2013 г.
UDP в Android: как приложения ищут друг друга в сети?
В большинстве случаев говря о передаче данных по сети мы имеем в виду TCP. Для большинства сетевых задач этот протокол лучший, но он вообще-то совсем не единственный. И есть вещи, которые с его помощью делать не удобно. Например: мы знаем порт, но не знаем IP-адреса получателя и нам нужно его найти. Опрашивать все адреса локальной сети по очереди? Жуть. Тут надо бы послать широковещательное сообщение, а для этого мы уже используем UDP. Этот протокол достаточно интересен. Например, мы можем слать сообщения и слушать на одном и том же проту одновременно. UDP при отправке широковещательных сообщений не создаёт соединения в привычном нам смысле. Мы не знаем, доставлено ли получателю наше UDP сообщение. Впрочем нам это и не нужно. Передавать данные мы будем уже по TCP. Итак как же экземплярам нашего приложения искать друг друга?
Кричим и слушаем одновременно
Этот класс — обычный поток, который открывает DatagramSocket и слушает его методом socket.receive(). При получении сообщения мы достаём текст и IP-адрес отправителя и передаём это методу onReceive() экземпляра класса BroadcastListener, который получили в конструкторе. Чтобы отправлять широковещательные сообщения используем метод send(). Заметьте, что сокет для отправки broadcast-ов мы открыли на том же порту, что и сокет для приёма сообщений. Никаких проблем с этим не возникает.
Как это использовать?
Делаем наш Pinger вложенным классом какого-нибудь Service, стартуем как обычный Thread и через очень короткое время имеем в переменной ips список IP-адресов всех кто шлёт сейчас запросы в нашей сети. Себя тоже мы там найдём, так что не забываем фильтровать свой IP-адрес. Скорость такого «поиска родственных душ» зависит только от задержки между пингами, которую (если не жалко трафика) можно сделать минимальной. Чтобы сохранять список IP-адресов актуальным, сохраняем время последнего пинга от данного клиента и вычищаем слишком «старые» адреса.
Источник
Стрим видео с Android устройства по UDP в JAVA приложение
Итак, выходим на финишную прямую. Стримить видео с андроида на VLC плеер мы уже научились, теперь осталось только интегрировать окошко с видео в JAVA приложение и начать рулить роботелегой.
В этом нам очень сильно поможет проект с открытым исходным кодом VLCJ CAPRICA.
The vlcj project provides a Java framework to allow an instance of a native VLC media player to be embedded in a Java application.
Идея у ребят простая, но гениальная (реально перцовая). Вместо мучений с библиотеками FFmpeg и прочим, надо сразу вызывать специалиста ядро нормального, функционального и профессионального медиаплеера VLC. И вызвать его прямо из JAVA приложения.
Кому интересно, просим под кат.
Поскольку, в этом вояже хватает подводных камней, то начнём, как водится, с очень простого и лишь затем перейдём к тривиальному.
Инсталляция пакета VLCJ
Первым делом проверьте установленную у вас версию медиапроигрывателя VLC. Свежая версия нам не нужна, там выпилено то, что требуется для udp стрима. Об этом уже говорилось в предыдущем посту. Поэтому качаем версию 2.2.6 Umbrella и заодно тщательно проверяем свой JAVA пакет. Они должны совпадать по разрядности. Если плеер использует 64-разрядную архитектуру, то и JDK обязан быть таким же. А то не взлетит.
После этого уже можно скачать сам пакет библиотек VLCJ
Обратите внимание, что нам нужен пакет vlcj-3.12.1 distribution (zip). Именно он работает с плеерами версий VLC 2.2.x. Разархивировать его можно куда угодно, главное, что не в папку самого VLC, ибо там по именам совпадают два файла. И если вы их перезапишите, кончится всё это полным провалом.
Далее, создаем проект в IDE IntelliJ IDEA (если у вас другое IDE, то ничем помочь не могу) и прописываем необходимые зависимости для интеграции библиотек VLCJ.
Делаем именно так для файлов:
Затем создаем единственный класс и пишем в нём следующую малюсенькую программку.
Да, пока мы пытаемся проигрывать просто файл (как видно из кода). С udp лучше не начинать — не заработает. А файл проигрывается вполне, если вы, конечно, не забыли его с соответствующим именем разместить заранее там, где надо. Думаю, что даже для самого начинающего джависта не составит труда разобраться в вышеприведенном коде.
и создание самого инстанса медиаплеера
А потом мы просто его добавляем в нужную графическую панель:
И всё, файл будет проигрываться именно в этом окошке.
А теперь попробуйте заменить
как мы спокойно делали в прошлом посте для стриминга видео через udp соединение.
Здесь такой номер не пройдёт. Окошко, конечно откроется, но покажет фигу, в смысле темный экран. Хотя никаких логов с ошибкой не будет. Просто не будет ничего.
Надо разобраться
Может быть не хватает кодека H264, который мы выбрали в настройках? Стоп, а как тогда только что проигрывался файл ttt.mp4? Он же не может проигрываться при такой настройке, он же — mp4.
Немедленно приходит понимание того, что библиотека VLCJ запускает только само ядро плеера. А какие там были предварительные настройки она не знает и знать не хочет. То есть, нам надо каким-то образом при запуске JAVA приложения, как-то передать VLC плееру, что мы хотим явно использовать кодек H264 или, допустим, хотим повернуть изображение или что-то ещё.
Оказывается, сделать это можно, используя класс MediaPlayerFactory. Только мы его запускали без аргументов, а можно даже с ними. На stackoverflow.com я тут же нашел простой пример, связанный с поворачиванием изображения:
То есть, чего-то там передаем строчным массивом в медиафабрику и оно там сохраняется для используемого медиаресурса.
Я попробовал этот способ для проигрывания файла и как водится, ничего не заработало. Оказывается, забыли две черточки добавить и разнесли по всему интернету. Пришлось догадываться, используя похожий метод transform.
Короче говоря, должно быть:
Теперь наш эталонный файл перекривило как надо!
Дальше будет уже совсем просто:
Для определения кодека, согласно командной строке VLC мы добавляем в строковый массив строку:
Снова пробуем udp канал
И в этот раз всё работает, обозначая победу человеческого разума. Теперь это окошко с видео или несколько таких окошек вы сможете беспрепятственно портировать в графический интерфейс вашего JAVA приложения.
Казалось бы победа?
Не совсем. Легкое недоумение у меня вызвали временные задержки или по научному, лаги. Сначала они более менее приёмлимые, но если у вас хватит терпения просмотреть видео до конца, то вы увидите, что лаг к концу первой минуты трансляции достигает аж пяти секунд. У меня терпения хватило на 10 минут съемки, но, как ни странно, задержка больше не увеличивалась, а так и осталась в тех же пределах.
Конечно, для просмотра видео с камеры такое сгодится, но для управления роботележкой едва ли. Даже луноход реагировал быстрее в два раза!
Подозрения сразу пали на процессы кэширования и они (подозрения )оказались верными.
Самым наглым оказался:
Он как раз и отжирает по умолчанию практически всё, если ему вовремя не дать по рукам.
Может устроить лаг и:
Поэтому во избежание многосекундных задержек рекомендуется добавить во всё тот же строковый массив через запятую следующие строчки:
Параметры там задаются в миллисекундах и поэтому каждый желающий может подобрать их под себя.
Ещё можно использовать ключ:
Тогда медиаплеер будет стараться оптимизировать джитер — подергивание экрана. Но там, чем больше установлено время, тем лучше оптимизируется и это понятно почему. Так что здесь остается лишь искать консенсус и видеть иногда в логах такое безобразие:
Вот хотел он, понимаешь, джиттер исправить, а ты временной промежуток слишком маленький поставил. Теперь сам виноват.
Теперь вроде бы все как надо. Задержку удалось сократить меньше, чем до одной секунды (правда, чуть-чуть меньше).
В итоге, получился совсем крохотный рабочий код
Теперь можно интегрировать видео трансляцию в мою программулину по управлению роботележкой, где раньше я передавал видео по кускам. И надо сказать код весьма упростился, а качество на порядок улучшилось. Плюс ко всему к видео потоку мы можем передать показания
акселерометров
гироскопов
уровня освещения
давления воздуха
показаний компаса
температуры
и даже влажности
При условии, конечно, что все эти сенсоры у вашего смартфона имеются.
И даже включить фару! Автоматически! Если уровень освещения упадёт.
Вряд ли кому особо интересно, но на случай ссылки на гитхаб:
Источник
Android-er
For Android development, from beginner to beginner.
Wednesday, June 1, 2016
Android Datagram/UDP Server example
I posted «Java Datagram/UDP Server and Client, run on raspberry Pi» on my another blogspot. And last post show «Android Datagram/UDP Client example». This post show a Datagram/UDP Server run on Android.
MainActivity.java
uses-permission of «android.permission.INTERNET» is needed in AndroidManifest.xml
Remark about life-cycle:
In this example, the DatagramSocket server is run in background thread. I haven’t handle the life-cycle very well (Actually I don’t think any application will have UI like this example). Consider the cases:
Case One:
— Start the app, the activity display on screen and the DatagramSocket opened in associated thread.
— the code socket.receive(packet) block the program flow, so the thread stay here and waiting data request.
— Exit the app. It will set running to false, to request the thread to stop. But the thread is blocked in socket.receive(packet), so it’s still running.
— Restart the app, the new thread cannot open the DatagramSocket, because it’s still held by old thread.
— Client send a request, the DatagramSocket server response the request and exit socket.receive(packet), and check running and exit.
— In this case, the current activity and associated thread have no DatagramSocket opened!
Case Two:
— Start the app, the activity display on screen and the DatagramSocket opened in associated thread.
— the code socket.receive(packet) block the program flow, so the thread stay here and waiting data request.
— Exit the app. It will set running to false, to request the thread to stop. But the thread is blocked in socket.receive(packet), so it’s still running.
— Client send a request, the DatagramSocket server response the request and exit socket.receive(packet), and check running and exit.
— Restart the app, and open the DatagramSocket.
— In this case, the current activity and associated thread can open DatagramSocket and work as expected.
5 comments:
Hi man, I appreciate your job, you are doing it really good. I want to ask that I create a socketserver on app and listening to port 8080,and I set system proxy as localhost:8080 so browsers are sending requests to app. I wonder how can I connect to requested url with request headers and send data to browser. Thanks for your business.
Hi;
Im curious about adding time when sending msg from client and the time when the server receive it, to find the transmission time in millisecond or in microsecond?
HI
how can put code to find the transmission time in milliseconds or microseconed?
thanks
Is there any limit on sending or receiving? I’m working sending and receiving lots of data, not concurrently, and my application is closing alone.
Tutorial is great, but it doesnot work on celluar internet connection.
you may have tested when you where on WIFI.
do you have any Tutorial on how to use celluar internet connection?
Источник
Основы программирования UDP-сокетов на Java
Сокеты — это абстракция самого низкого уровня для программистов, работающих в области сетевого программирования. Существует в основном два способа (протокола) того, как должна происходить коммуникация сокетов.
Один из способов устанавливает набор правил и механизмов, ограничивающих коммуникацию, так, что вероятность возникновения ошибки делается очень низкой, но эти дополнительные элементы управления сами замедляют коммуникацию.
Он называется TCP (Transfer Control Protocol). В противоположность этому, другой способ имеет очень мало правил, и поэтому он ускоряет общение, но не гарантирует точность. Он называется UDP (User Datagram Protocol). Если вам будет дан шанс выбрать один из них, какой вы выберете?
Я не собираюсь подробно обсуждать разницу между TCP и UDP, потому что это выходит за рамки данной статьи. Тем не менее, когда мы хотим, чтобы коммуникация была точной, мы должны воспользоваться TCP, потому что это помогает обеспечить бесперебойную связь.
Если вы знакомы с TCP, то наверняка знаете, что он реализует различные механизмы, такие как управление потоком, контроль ошибок, контроль перегрузки и т.д. Однако, когда нашим главным приоритетом является быстрая коммуникация, а не точная, выбор должен быть сделан в пользу UDP.
В этой статье мы узнаем, что такое UDP-сокеты и как продемонстрировать коммуникацию UDP-сокетов, используя Java.
Но почему именно UDP?
Скорость — основной приоритет для потоковой передачи в реальном времени. Когда футбольный матч транслируется в режиме реального времени, люди, которые смотрят его по телевидению, должны получать обновленную информацию о событиях сразу же, как только они происходят на игровой площадке.
Неспособность поставлять контент в режиме реального времени может критически сказаться на росте поставщика потоковой передачи и его позиции на рынке.
Кроме того, нет никакой пользы в повторной трансляции точных данных, даже если контент был поврежден на пути к конечному пользователю, просто потому, что они больше не являются “контентом в реальном времени”. По этим причинам при взаимодействии в реальном времени UDP предпочтительнее TCP.
Примечание: если вы хотите получить представление о том, что такое сокеты и как работает коммуникация TCP-сокетов, пожалуйста, ознакомьтесь с этой статьей.
- socket() — прежде всего сокет определяется как для сервера, так и для клиента. Это не обязательно должно происходить одновременно. Чтобы объяснение было исчерпывающим, я буду на каждом этапе обсуждать действия как сервера, так и клиента.
- bind() — сокету, который определен, присваивается идентификатор и порт на работающей машине. Для клиентского сокета это необязательно, потому что даже если клиентский сокет не привязан, привязка осуществляется автоматически всякий раз, когда клиент инициирует подключение к серверу.
- recvfrom() — после привязки к порту компьютера серверный сокет ожидает подключения от клиентского сокета. Тем временем дальнейшее выполнение текущего потока останавливается (блокируется) до тех пор, пока серверный сокет не получит соединение. То же самое происходит и с клиентским сокетом при ожидании ответа сервера.
- sendto() — после соединения с клиентом серверный сокет отправляет данные клиенту. Этот же метод используется клиентским сокетом для выполнения запроса на подключение к серверу.
- close() — после успешного обмена данными оба сокета закрываются, т.е. освобождаются ресурсы системы, выделенные для сокетов.
Коммуникация UPD-сокетов в действии
Классы DatagramPacket и DatagramSocket в Java поддерживают использование коммуникации UDP-сокетов на уровне приложения. Давайте напишем простой сервер и клиент на Java, которые взаимодействуют друг с другом через UDP-сокеты.
В этом примере серверный сокет получает данные типа String от клиента и отправляет заглавную строку обратно клиенту.
Поскольку мы уже осведомлены об этапах коммуникации UDP-сокетов, я поместил комментарии в обе Java-программы, чтобы объяснить код, а не использовать длинные абзацы. Этот способ также поможет вам быстрее понять код, пока вы будете его читать.
Построение серверного UDP-сокета
Создание клиентского UDP-сокета
Запуск программ: демонстрация работы сокетов
Поскольку мы уже создали и сервер, и клиента, давайте запустим обе программы и посмотрим их в действии. Сначала запустите программу UDPServer.java , а затем UDPClient.java .
Вы увидите на консоли/терминале вывод каждой программы, как это показано ниже. Это гарантирует, что между нашими сервером и клиентом произошла успешная коммуникация сокетов.
UDPServer.java
UDPClient.java
Вот наше руководство и подошло к концу. Из этой статьи мы узнали, что такое коммуникация UDP-сокетов и как ее продемонстрировать на Java. Я искренне надеюсь, что информация вам пригодится.
Источник