ZP+TCP/IP Передаем статус проекта на мобильное устройство

Serkser

Client
Регистрация
26.01.2015
Сообщения
90
Реакции
344
Баллы
53
Всем доброго дня!
В этой статье я бы хотел Вам рассказать о таком протоколе передачи данных как TCP/IP и как его можно использовать в своих проектах.

Чуть чуть теории
Переводя определение с википедии, можно сказать что этот протокол позволяет серверу и клиенту установить один общий буффер данных, в который любая из сторон может вписывать информацию, а другая получить уведомление об этом и прочитать ее + TCP гарантирует доставку всех пакетов без потерь в отличии от UDP.

Ближе к делу
В моем примере сервером будет выступать шаблон ZP, а клиентом станет мобильное приложение.
Хотя на самом деле клиента можно написать и на другом шаблоне и обмениваться данными между ними даже если они физически находятся в двух разных уголках планеты =)

Для создания шаблона- сервера нам понадобится библиотека Interop.NATUPNPLib (во вложении). Она необходима для того чтобы пробросить порт через ваш локальный IP адрес и роутер, который имеет внешний IP адрес, чтобы вы смогли подключаться к своему проекту через интернет, а не только находясь в одной локальной сети.

Добавляем ссылку на библиотеку в шаблон и начинаем кодить:
Во вкладке общего кода у вас должны быть следующие using
Код:
Развернуть Свернуть Копировать
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text.RegularExpressions;

Объявляем нужные нам переменные:

Код:
Развернуть Свернуть Копировать
         static NATUPNPLib.UPnPNAT upnpnat = new NATUPNPLib.UPnPNAT();
         static IPAddress ipAd;
         static TcpListener listener;
         static Socket socket;

Первый метод для получения своего локального адреса
Код:
Развернуть Свернуть Копировать
public static IEnumerable<IPAddress> GetLocalIPAddress()
        {
           return Dns.GetHostEntry(Dns.GetHostName()).AddressList.Where(f=> f.AddressFamily == AddressFamily.InterNetwork);
        }

Далее метод для получения статуса соединения
Код:
Развернуть Свернуть Копировать
public static bool IsConnected(this Socket sockets)
         {
           try
           {
             return !(sockets.Poll(1, SelectMode.SelectRead) && sockets.Available == 0);
           }
           catch (SocketException) { return false; }
         }

Самый важный метод - запуск сервера и старт ожидания соединения
Код:
Развернуть Свернуть Копировать
public static bool StartConnection()
        {
            string ipAddres = string.Empty;
            if (GetLocalIPAddress().Any()) //получаем свой локальный ip адрес
                ipAddres = GetLocalIPAddress().First().ToString();
            else
                return false;
             ipAd = IPAddress.Parse(ipAddres);
             listener = new TcpListener(ipAd, 20903);
             listener.Start();// запуск сервера
            // делаем проброс порта через роутер
            NATUPNPLib.IStaticPortMappingCollection mappings = upnpnat.StaticPortMappingCollection;
            if(mappings !=null)
            mappings.Add(20903, "TCP", 20903, ipAddres, true, "Port for ZennoPoster"); //если требуется пробрасываем порт
          new Thread(()=> socket = listener.AcceptSocket()).Start(); // ожидание подключения в фоновом потоке
            return true;
        }

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

Метод передачи сообщения
Код:
Развернуть Свернуть Копировать
//метод отправки сообщения клиенту
        public static bool SendMessage(string text)
        {
            if(socket ==null)
                return false;
            try{
            byte[] bytes = Encoding.GetEncoding(1251).GetBytes(text);
            socket.Send(bytes);
                return true;
            }
            catch{return false;}
            finally{
            if(!socket.IsConnected() && socket != null)
            {StopConnection();
                StartConnection();
            }
            }
        }
Грубо говоря мы просто взяли текст, перевели его в массив байтов и отправили по сокету

Отправка файла, а в нашем случае мы будем отправлять каптчу
Код:
Развернуть Свернуть Копировать
//метод отправки файла клиенту
        public static string SendCaptcha(string filePath)
        {
            if(socket ==null)
                return "";
            try{
            byte[] bytes = Encoding.GetEncoding(1251).GetBytes("isFile "+File.ReadAllBytes(filePath).Length);
            socket.Send(bytes);
            socket.Receive(bytes);
            socket.Send(File.ReadAllBytes(filePath));
            bytes = new byte[1024];
           int lenght= socket.Receive(bytes);
            return Encoding.GetEncoding(1251).GetString(bytes);
            }catch{return "";}
            finally{
            if(!socket.IsConnected() && socket != null)
            {StopConnection();
            StartConnection();
            }
            }
        }
Тут по сложнее. В коде можно увидеть две отправки пакета байтов, первым я передаю флаг в виде слова "isFile" + размер файла, который я собираюсь передать. Далее ожидаю ответа от клиента и уже отправляю чистый файл, переведенный в массив байтов. Зачем такой кастыль?) Да потому что стандартный метод передачи файла по сокету почему то убивает PM, поэтому я решил сделать вот так. Да и везде говорят что при таком подходе быстрее файл передается чем уже готовым методом =)

Ну и последний метод закрытия соединения
Код:
Развернуть Свернуть Копировать
        //метод остановки соединения
        public static void StopConnection()
        {
            try{
            if(socket!= null)
            socket.Disconnect(true);
            if(listener!= null)
            listener.Stop();
            NATUPNPLib.IStaticPortMappingCollection mappings = upnpnat.StaticPortMappingCollection;
            mappings.Remove(20903, "TCP");
            }catch{}
        }

Суть написания клиента
В первую очередь на клиенте нужно произвести соединение с сервером:
Код:
Развернуть Свернуть Копировать
               IPEndPoint ipep =
                   new IPEndPoint(IPAddress.Parse("Внешний ip сервера"), 20903);
               Socket server = new Socket(AddressFamily.InterNetwork,
                   SocketType.Stream, ProtocolType.Tcp);
                       await server.ConnectAsync(ipep);

Для того чтобы дождаться и получить данные от сервера делаем так
Код:
Развернуть Свернуть Копировать
byte[] data = new byte[1024]; //готовим массив, куда будет сложен ответ
                      int lenght = socket.Receive(data); //наполняем этот массив, одновременно получая его длину
                      string text = Encoding.GetEncoding(1251).GetString(data, 0, lenght);// переводим массив в строку

Отправка данных от клиента к серверу
Код:
Развернуть Свернуть Копировать
       byte[] dataBytes = Encoding.GetEncoding(1251).GetBytes("текст который передаем");
                    socket.Send(dataBytes); //отправляем

Таким образом на выходе получаем следующее:
Как видно в демонстрации на телефоне у меня обычное мобильное соединение, а на ПК домашний WIFI, данные передаются достаточно быстро=)

Исходники клиента можете скачать или посмотреть тут (Xamarin):
https://bitbucket.org/serkser70/clientzp

Запакованый APK клиента (форум не принимает apk файлы, залил на яндекс):
https://yadi.sk/d/6PBUMW4K3N9rzD

Библиотека:
https://yadi.sk/d/bVgw5GPl3N9ryh

На этом все =)

Я понимаю что для некоторых эта статья покажется слишком мудреной и сложной, но тем не менее искренне верю, что кому то это откроет новый взгляд на построение своих проектов и поможет реализовать крутые идеи!
А для новичков это не лишнее доказательство безграничных возможностей ZennoPoster!

Всем огромное спасибо за внимание! Я очень рад снова участвовать в этом конкурсе!=)
 
Номер конкурса статей
  1. Седьмой конкурс статей
Тема статьи
  1. Другое

Вложения

Последнее редактирование:
офигенная статья, в очередной раз буду голосовать за автора..
 
как на счёт продолжения статьи на примере взаимодействия с каким-нибудь чатиком в вебе, который по tcp устроен, желательно еще и через прокси, если возможно?)
 
даже не предполагал что зп так умеет, спасибо за статью
 
  • Спасибо
Реакции: Serkser
ни че не понял)
 
  • Спасибо
Реакции: zennoX
Круто теперь каптчи можно с телефона гадать :-)
Какие еще применения можно этому найти? Отправлять статистику о работе шаблона на телефон?
Спасибо за либу Interop.NATUPNPLib - не знал про такую, может пригодиться в обычных C# приложениях
 
Последнее редактирование модератором:
  • Спасибо
Реакции: Serkser
Interop.NATUPNPLib где?
 
Круто теперь каптчи можно с телефона гадать :-)
Какие еще применения можно этому найти? Отправлять статистику о работе шаблона на телефон?
Спасибо за либу Interop.NATUPNPLib - не знал про такую, может пригодиться в обычных C# приложениях
чат ботов пилить в терии взаимодействовать с приложениями на телефоне или на виртуалках запущеных актуально для вацапа очень, и инсты и прочей юлы))) аля зенодроид многопоточный я както так понял сей посыл )))
 
Последнее редактирование модератором:
  • Спасибо
Реакции: Serkser
Сразу выражая недовольство некоторыми пунктами реализации:
1)
Код:
Развернуть Свернуть Копировать
new Thread(()=> socket = listener.AcceptSocket()).Start();
Зачем поднимать целый поток ради слушателя? Есть пул потоков, а также async/await
2)
Код:
Развернуть Свернуть Копировать
byte[] bytes = Encoding.GetEncoding(1251).GetBytes(text);
            socket.Send(bytes);
Байты можно сжать с помощью qzip/deflate стримов
Если для автора это первый опыт работы с сервером-клиентом, то тут простительно.
 
  • Спасибо
Реакции: Lord_Alfred
Сразу выражая недовольство некоторыми пунктами реализации:
1)
Код:
Развернуть Свернуть Копировать
new Thread(()=> socket = listener.AcceptSocket()).Start();
Зачем поднимать целый поток ради слушателя? Есть пул потоков, а также async/await
2)
Код:
Развернуть Свернуть Копировать
byte[] bytes = Encoding.GetEncoding(1251).GetBytes(text);
            socket.Send(bytes);
Байты можно сжать с помощью qzip/deflate стримов
Если для автора это первый опыт работы с сервером-клиентом, то тут простительно.
Спасибо за замечания)
Поскольку данных передавал немного то насчет компрессии не стал заморачиваться. А с ассинхронностью я бы с удовольствием, но чего то при ее использовании PM отваливался часто, поэтому сделал на треде
 
Автор, я тебе по IP вычислю :D.

Вроде не сложно, кроме кода конечно =) А где применять такое можно?
Все зависит от твоей фантазии, ты можешь установить ZP на 100 серверов, а на своем пк написать шаблон, который будет отправлять команды с поручениями каждому твоему шаблону на сервере, а потом если тебе нужно срочно куда то идти, ты сможешь взять телефон и продолжишь управлять проектами даже по низкому интернет соединению)
 
  • Спасибо
Реакции: KitKat21
как на счёт продолжения статьи на примере взаимодействия с каким-нибудь чатиком в вебе, который по tcp устроен, желательно еще и через прокси, если возможно?)
Возможно абсолютно все, главное желание, постараюсь написать после конкурса статью про сниффинг и реверсинг TCP протоколов, но сейчас пока времени не особо =)
 
искренне верю, что кому то это откроет новый взгляд на построение своих проектов и поможет реализовать крутые идеи!
Статья просто супер, и ведь правда это может очень помочь в реализации разных идей и управлении своими проектами!!!
ТС буду голосовать за вашу статью,как и на прошлом конкурсе
 
  • Спасибо
Реакции: Serkser
Интересная статья! Но нужно подумать как лучше всего развить эту идею для реализации чего-то своего, т.к. банальные штуки вроде "управления зенкой с мобилки", "решение капчи на мобилке" - вряд ли кому-то нужны.

Тут лучше, пожалуй, задуматься о том, что с помощью Interop.NATUPNPLib можно сделать свой ботнет/супер-проксификатор. Т.е. сделать сервером не зенку, а свою приложеньку, которую эксплоитить по-чёрному на другие машины, в этой приложеньке делать отстук на определенный сервер, чтобы показать что эта нода готова принимать команды, а потом с зенки стучаться по всем нодам и юзать всё это добро как огромный проксификатор.
 
  • Спасибо
Реакции: Serkser
Статье нужно найти более лучшее применение, чем гадание капчи. Или мне кажется или просто пока не все понятно, но не проще отснифать приложение и работать с автоматизированным процессом на автомате. Может быть с какими то зашифрованными приложениями ваше решение более подходящее.
 
Каждый может использовать информацию из статьи как ему угодно, я рассматривал самый простой вариант дабы было нагляднее =)
 
  • Спасибо
Реакции: SHoro
огромное спасибо за статью, техническая часть очень полезна!
 
  • Спасибо
Реакции: Serkser
Это решение очень актуально, если делать из проекта веб-сервис. Тогда на Зенке будет бэк-энд (сервер, который делает всю работу), а где-то на хостинге - просто веб-морда, которая транслирует в Зенку запросы пользователей. Без этого решения веб-морде оставалось бы только ожидать, пока Зенка сама её дёрнет и спросит, чё как — а тут фронтенд может сам к бэкенду обращаться, всё как надо. Полезная вещь! Так, чё-то я расщедрился на похвалы, а я ж конкурент в этом конкурсе))
 
получается так можно скрыть работу шаба от снифера?
 
  • Спасибо
Реакции: Serkser
Это решение очень актуально, если делать из проекта веб-сервис. Тогда на Зенке будет бэк-энд (сервер, который делает всю работу), а где-то на хостинге - просто веб-морда, которая транслирует в Зенку запросы пользователей. Без этого решения веб-морде оставалось бы только ожидать, пока Зенка сама её дёрнет и спросит, чё как — а тут фронтенд может сам к бэкенду обращаться, всё как надо. Полезная вещь! Так, чё-то я расщедрился на похвалы, а я ж конкурент в этом конкурсе))

Плюс еще можно в сокет сливать весь видеопоток происходящего и смотреть прямую трансляцию того что делает шаблон)))
 
Плюс еще можно в сокет сливать весь видеопоток происходящего и смотреть прямую трансляцию того что делает шаблон)))
Можете показать пример каким образом записывать этот же видеопоток происходящего в файл?
 
Можете показать пример каким образом записывать этот же видеопоток происходящего в файл?
На самом деле изнутри это будет выглядеть как множество скриншотов, делаемых каждую милисекунду и вписываемых во фреймы видеопотока
 
  • Спасибо
Реакции: BAZAg
можно-же все это сделать через api телеграм?
 
Ссылки на скачивание с Я.Диска не активны. Автор, можете новые ссылки написать?
 

Кто просматривает тему: (Всего: 0, Пользователи: 0, Гости: 0)