Страницы

Поиск по вопросам

Показаны сообщения с ярлыком клиент-сервер. Показать все сообщения
Показаны сообщения с ярлыком клиент-сервер. Показать все сообщения

четверг, 9 апреля 2020 г.

Как реализовать переход между activity сохраняя сокет-соединение?

#java #android #клиент_сервер

                    
Пробую свои силы в клиент-серверах и наткнулся на такую проблему, если я хочу чтобы
на стороне клиента после подключения к серверу сменился Activity, но соединение не
потерялось, то как это реализовать понять не могу. 
Подключение клиента реализовывал в AsyncTask, который получается привязан к одному
Activity.

Для наглядного понимания вот пример: 

Допустим все клиенты сначала собираются в "комнате", а после того как все подключились
дается команда перейти на другое Activity с вопросами. Что-то типо онлайн викторины
где все стартуют одновременно.
    


Ответы

Ответ 1



есть один вариант. Запускать этот AsyncTask только один раз, и тогда можно будет обращаться к нему из любого Activity. public class DownloadWebPageTask extends AsyncTask { private static DownloadWebPageTask downloadWebPageTask; private Socket socket; // Это для соединения с сервером private DownloadWebPageTask(){ } public static synchronized DownloadWebPageTask getInstance( ) { if (downloadWebPageTask == null) downloadWebPageTask = new DownloadWebPageTask (); return downloadWebPageTask; } //... } использовать так (из любого Activity) DownloadWebPageTask downloadWebPageTask = DownloadWebPageTask.getInstance(); downloadWebPageTask.execute(a, b, c);

воскресенье, 15 марта 2020 г.

Реализация клиент-серверного приложения

#c_sharp #aspnet #сокет #wcf #клиент_сервер


Имеется следующая архитектура: клиентская часть(dll-ка на C#) отсылает определенное
количество картинок на сервер(либо Windows Service, либо Web Service), где они обрабатываются,
а потом отсылается ответ в виде XML файла результатов обработки.

Клиент - это просто автоматизированное приложение, без интерфейса и ввода вывода. 

Сервер. На нем крутится движок, использующий многопоточность (с помощью ThreadPool)
для обработки картинок.
Соответственно, когда обращается новый клиент, сервер создает новый поток, в котором
происходит обработка, по окончанию он отсылает ответ пользователю(xml-файл).
Нагрузка на сервер планируется не очень большая 3-20 одновременных подключений.

Пока что я не могу понять какая архитектура взаимодействия лучше всего подойдет для
моего случая. Есть несколько путей реализации, либо писать асинхронный сервер на сокетах,
либо использовать WCF, или просто написать ASP.NET приложение и залить его на IIS(к
этому варианту я склоняюсь больше всего).

Какой протокол передачи лучше всего использовать? Хватит ли HTTP для передачи большого
количества картинок(тогда можно двигаться в направлении Web Service), или стоит задуматься
о TCP/IP(здесь уже WCF)?

Кому интересно, несколько статей по созданию клиент-серверного приложения:

Example with ASYNC/AWAIT

Example with THREADS

Example with SOCKETS
    


Ответы

Ответ 1



HTTP, WCF и голый TCP справляются с заливкой картинок примерно одинаково. Особенно если учесть, что HTTP работает поверх TCP, а WCF - или поверх HTTP, или с собственным протоколом поверх TCP, в зависимости от настроек биндинга. Никакой ощутимой разницы между реализациями с точки зрения производительности не будет. То же самое с типом хостинга - между Self-Hosted и IIS нет практически никакой разницы (не при вашей нагрузке). Вам стоит использовать то, что вам удобнее в написании и поддержке.

пятница, 28 февраля 2020 г.

Ошибка при вызове WSAPoll()

#cpp #c #winapi #клиент_сервер #winsock


Пишу простой UDP сервер под Windows, который принимает сообщения от клиентов. По
заданию сокеты должны работать в неблокирующем режиме и обязательно нужно использовать
WSAPoll для параллельного обслуживания клиентов. Написал небольшую обертку для сокета:

class _socket
{
private:
    SOCKET      sock;
    sockaddr_in addr;
public:
    _socket(int port);
    _socket(const _socket & other);
    ~_socket();

    SOCKET GetSocket();
    bool   Generate();
    bool   Bind();
};

_socket::~_socket() 
{
    if (sock != INVALID_SOCKET) 
    {
        closesocket(sock); 
    } 
}

_socket::_socket(int port) : sock(INVALID_SOCKET) 
{
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port); 
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
}

_socket::_socket(const _socket & other)
{
    this->sock = other.sock;
    this->addr = other.addr;
}

SOCKET _socket::GetSocket()
{
     return (this->sock); 
}
bool _socket::Generate()
{
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        return false;
    }
    else
    {
        unsigned long mode = 1;
        return (ioctlsocket(sock, FIONBIO, &mode) != SOCKET_ERROR);
    }
}
bool _socket::Bind()
{
    return (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) >= 0);
}


Вот так работаю с ним в main (через argv передаю диапазон портов):

int main(int argc, const char *argv[])
{
    std::vector<_socket>        sockets;
    std::map clients;

    if (argc < 3)
    {
        return ErrorPrint("Too low arguments");
    }
    if (!Init())
    {
        return ErrorPrint("Error starting WSA");
    }

    for (int i = atoi(argv[1]); i <= atoi(argv[2]); i++)
    {
        _socket s(i);
        if (!s.Generate())
        {
            return ErrorPrint("Cannot create socket");
        }
        if (!s.Bind())
        {
            return ErrorPrint("Cannot bind socket");
        }
        sockets.push_back(s);
    }

    WSAPOLLFD *pfd = (WSAPOLLFD*)malloc(sockets.size() * sizeof(WSAPOLLFD));

    for (int i = 0; i < sockets.size(); i++)
    {
        pfd[i].fd      = sockets[i].GetSocket();
        pfd[i].events  = POLLIN | POLLOUT;
        pfd[i].revents = 0;
    }

    while (true)
    {
        int ev_cnt = WSAPoll(pfd, sockets.size(), 1000);
        if (ev_cnt > 0)
        {
            for (int i = 0; i < sockets.size(); i++)
            {
                if (pfd[i].revents & POLLERR)
                {

                }
                if (pfd[i].revents & POLLIN)
                {

                }
                if (pfd[i].revents & POLLOUT)
                {

                }
            }
        }
        else if (ev_cnt == SOCKET_ERROR)
        {
            std::cout << "Error WSAPoll: " << WSAGetLastError() << std::endl; //
Постоянно попадаю сюда
        }
        else
        {
            std::cout << "waiting..." << std::endl;
        }
    }

    return (EXIT_SUCCESS);
}


При вызове WSAPoll постоянно получаю ошибку WSAENOTSOCK (10038), которая говорит
мне, что я пытаюсь выполнить операцию, предназначенную для сокета на чем-то, что им
не является. Прочитал спецификации к WSAPoll - вроде все делаю правильно, никак не
могу понять, что сделал не так.
    


Ответы

Ответ 1



У вас реализован конструктор копирования после выполнения которого в двух экземплярах класса будет хранится один и тот же дескриптор сокета. После разрушения одного из экземпляров второй останется с невалидным дескриптором. Следовало реализовать конструктор перемещения (и перемещающий оператор присваивания): _socket(const _socket & other) = delete; _socket(_socket && other) : sock{other.sock} , addr{other.addr} { other.sock = INVALID_SOCKET; ::std::memset(::std::addressof(other.addr), 0, sizeof(other.addr)); } Сокеты на самом деле можно дублировать используя WSADuplicateSocket, но обычно это не нужно.

среда, 26 февраля 2020 г.

О чём они общаются!?

#клиент_сервер


Как посмотреть (какой программой), какой информацией обмениваются Клиент с Сервером?
Ну, к примеру, веб-сервер с браузером, хотя вопрос стоит для протокола неизвестной
архитектуры...    


Ответы

Ответ 1



Для этой задачи можно использовать Wireshark

понедельник, 24 февраля 2020 г.

Сервер-клиент на Java

#java #клиент_сервер


Необходимо сделать Сервер-Клиент.

Со стороны сервера - таблица с именами работников и их ID . 

Со стороны клиента - программа для добавления нового сотрудника и вытягивания всей
таблицы.

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


Ответы

Ответ 1



Если хотите писать велосипед, то вот самый быстрый на руку вариант клиент-серверного взаимодействия. Сервер: class TCPServer{ public static void main(String argv[]) throws Exception{ String clientSentence; String capitalizedSentence; ServerSocket welcomeSocket = new ServerSocket(6789); while(true){ Socket connectionSocket = welcomeSocket.accept(); BufferedReader inFromClient = new BufferedReader(new InputStreamReader(connectionSocket.getInputStream())); DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream()); clientSentence = inFromClient.readLine(); System.out.println("Received: " + clientSentence); capitalizedSentence = clientSentence.toUpperCase() + '\n'; outToClient.writeBytes(capitalizedSentence); } } } Клиент: class TCPClient{ public static void main(String argv[]) throws Exception{ String sentence; String modifiedSentence; BufferedReader inFromUser = new BufferedReader( new InputStreamReader(System.in)); Socket clientSocket = new Socket("localhost", 6789); DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream()); BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); sentence = inFromUser.readLine(); outToServer.writeBytes(sentence + '\n'); modifiedSentence = inFromServer.readLine(); System.out.println("FROM SERVER: " + modifiedSentence); clientSocket.close(); } } Если нужно нормальное решение, то сервлеты, или какую-то библиотеку вроде netty. Для работы с базой использовать какую-нибудь ORM вроде Hibernate.

Клиент-сервер на разных языках

#java #c_sharp #клиент_сервер


Можно ли сделать сервер на c#, а клиент на java? 
    


Ответы

Ответ 1



Конечно можно. Почему нет? Сервер и клиент в общем случае могут быть написаны на любом подходящем языке программирования. Единственное требование они должны использовать,скажем так, общий формат взаимодействия. Достигается это с помощью таких вещей как, например, TCP, REST, SOAP.

Шаблонизация в веб приложениях: сервер, клиент, смешанная?

#angularjs #сервер #клиент_сервер #проектирование #веб_программирование


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

1. Клиентская шаблонизация с json rest api

Достаем из базы данные => отдаем их на клиент в json/xml => разбираем данные на клиенте,
создавая объекты по клиентским моделям => добавляем каждую полученную модель в DOM. 

плюсы:  


пользователь ждет только нужные ему данные  
в процессе загрузки данных можем показать красивый прелоадер


минусы:


дублируем модели
лишний раз напрягаем клиентский браузер шаблонизацией


2. Тоже rest api, только шаблонизация, в целом, серверная

Достаем из базы данные => создаем из них html код => отдаем на клиент html => на
клиенте просто пихаем полученный html в DOM не думая.
Этот способ мне кажется самым практичным, но о нем почему-то практически не пишут.
Я просто что-то не то читаю, или есть серьезные недостатки, которых я просто не вижу?

плюсы:


первых два из пункта выше  
не дублируем модели


минусы:


выглядит так, будто их нет


3. Классическая серверная шаблонизация... только сервер

Выбираем данные из базы => на сервере это все дело делаем в html, но не кусочек страницы,
а всю страницу целиком => отдаем на клиент заново всю страницу.

плюсы:


не дублируем модели


минусы:


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


Вопросы


Какие еще есть вариации?
Кто что использует в своих проектах (личных, рабочих, как делают крупные компании...)? 
Почему? 
Какие плюсы и минусы я пропустил/не понял? 
В каком случае что использовать лучше? 

    


Ответы

Ответ 1



Кто что использует в своих проектах (личных, рабочих, как делают крупные компании...)? Крупная компания, более 20 разработчиков на проекте бывает. Либо полный server-side, либо полностью client-side, смешивание только в очень специфичных случаях (возможно бывают такие, сам не встречал). Server-side для проектов, где можно обеспечить full-stack разработчиков, чтобы и сверстать по мелочи, и скрипт на JS написать и запрос к базе сформировать смогли и т.д. Мобильные приложения не требуются, предоставления API для третьих лиц тоже. Чаще всего проекты, где веб-интерфейс минимален перспектив развития интерфейса нет. Client-side если команда большая, разделить можно на фронтэндщиков, бекендщиков, мобильщиков. Минусы - расходы на поддержку линии API. Чаще всего такой подход применяем, причем API first (у нас RAML). Была пара проектов в практике, где ответственность за отображение поделили между сервером и клиентом, очень неприятные впечатления: постоянные вопросы о том, кто за что должен отвечать, вопросы согласованности (например динамически формируемая форма на клиенте и ее перезаполнение в случае ошибочного сабмита). Требования к разработчикам очень высокие, нужно знать и client-side и server-side технологии.

Ответ 2



Во втором случае на самом деле есть куча минусов (кстати, слова "REST API" к нему неприменимы - потому что это не REST и не API). во-первых, возможности разметки в таком режиме получаются "обрезанными" - в частности, многие способы вставки HTML-кода в документ не запускают скрипты; во-вторых, страница, изготовленная из кучи надерганных кусков обычно является кошмаром верстальщика - совершенно не понятно в каком вообще файле надо искать нужный кусок верстки; в-третьих, постоянное дерганье innerHTML негативно сказывается на производительности; в-четвертых, такое решение обычно требует больше трафика чем оба альтернативных. Из плюсов же у него - поддержка большинством серверных фреймворков. По первому варианту - если вы не пишите ничего сложного, то "шаблонизация" клиентский браузер не напрягает. Особенно если использовать не шаблонизаторы, а библиотеки для двунаправленной привязки данных. Дублирование моделей тоже не является особенностью первого варианта - зачастую клиентская модель, серверная модель и модель передачи являются совершенно разными - и это совершенно нормально. Фактически, при переходе от тертьего варианта к первому модель не дублируется, а разделяется на две.

пятница, 31 января 2020 г.

С#: передача параметров с POST запросом

#c_sharp #веб_программирование #клиент_сервер


Столкнулся с интересно задачей - требуется на сервер послать параметры и в ответ
получить XML.

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(is_card_URL);
request.Method = "POST";

byte[] bytes = Encoding.UTF8.GetBytes(params_);
request.ContentLength = bytes.Length;

using (var stream = request.GetRequestStream())
{
    stream.Write(bytes, 0, bytes.Length);
    stream.Close();
}

HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream stream2 = response.GetResponseStream();
StreamReader reader = new StreamReader(stream2);

string data = reader.ReadToEnd();

reader.Close();
stream2.Close();


Сам код работает, но нужно вместе с УРЛ также послать параметры (допустим, а,b,c)
Я пробовал дописывать в УРЛ (...?a=1&b=2&c=3), но сервер не видит параметров, в ответе
он пишет, что параметры не переданы.

Подскажите пожалуйста, как в данном случае можно передать параметры на сервер?
    


Ответы

Ответ 1



Параметры для POST запроса передаются немного по-другому: string postParameters = "a=1&b=2&c=3"; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(is_card_URL); request.Method = "POST"; request.ContentLength = postParameters.Length; using (var writer = new StreamWriter(request.GetRequestStream())) { requestWriter.Write(postParameters); } Если передаваемая строка может содержать недопустимые символы, ее предварительно нужно закодировать: string parameters = ...; string postParameters = HttpUtility.UrlEncode(parameters); Дополнительно можно указать желаемую кодировку: using (var writer = new StreamWriter(request.GetRequestStream(), Encoding.UTF8)) В общем случае, когда нужно передать произвольные данные, используется байтовый массив: byte[] postData = ...; request.ContentLength = postData.Length; using (var stream = request.GetRequestStream()) { stream.Write(postData, 0, postData.Length); } Тогда пример с передачей строки можно свести к следующему коду: string parameters = ...; byte[] postData = Encoding.UTF8.GetBytes(HttpUtility.UrlEncode(parameters)); request.ContentLength = postData.Length; using (var stream = request.GetRequestStream()) { stream.Write(postData, 0, postData.Length); }

Ответ 2



Если нет принципиальной необходимости работать именно через WebRequest/WebResponse, то самый простой способ - использование System.Net.WebClient.UploadValues using (WebClient client = new WebClient()) { byte[] response = client.UploadValues(is_card_URL, new NameValueCollection() { { "a", "1" }, { "a", "2" }, { "c", "3" } }); string result = UTF8.GetString(response); }

Ответ 3



В отличие от GET-запроса POST получает параметры в теле, а не в строке запроса, а размер передаваемых данных указывается в заголовке ContentLength. Сделайте например так: byte[] bytes = Encoding.UTF8.GetBytes(queryString); webRequest.ContentLength = bytes.Length; using (var stream = webRequest.GetRequestStream()) { stream.Write(bytes, 0, bytes.Length); stream.Close(); } Плюс небольшая ремарка: никогда не используйте просто Close/Dispose без using или try для потоков, запросов и прочих освобождаемых ресурсов. Это источник потенциальных проблем

Что такое php echo?

#php #клиент_сервер #rest


Существующее определение: "вывод текста". Куда echo выводит текст? И каким образом
браузер этот текст получает?

В интересующем меня случае: если браузер отправляет http get-запрос серверу, то через
echo в итоге от сервера клиенту посылается так же get ответ?
    


Ответы

Ответ 1



Браузер отправляет запрос с указанием IP адреса сервера (вычисляется по имени домена при помощи DNS сервера) Номера порта (по умолчанию 80 для http и 443 для https) Адреса страницы на этом сервере Веб-сервер, который сидит на указанном IP адресе и который слушает указанный порт получает TCP-пакет, достает из него адрес страницы и смотрит, кто этот адрес будет обрабатывать (алгоритм поиска обработчика - вопрос отдельный) Создает настройки окружения и запускает обработчик Если был вызван PHP обработчик, то он создает буфер вывода и выполняет нужный скрипт Скрипт, при помощи команд echo, header, setcookie заполняет этот буфер PHP обработчик после окончания работы скрипта, или по мере заполнения буфера, отдает этот буфер запустившему веб-серверу. Веб-сервер может дополнительно обработать этот буфер (например, сжать его) и отправляет по TCP запросившему клиенту Браузер получает TCP пакет, достает и обрабатывает содержимое

среда, 29 января 2020 г.

Актуализация информации

#c_sharp #net #wcf #веб_программирование #клиент_сервер


Есть Клиент, который работает с WCF службой.

WCF служба в свою очередь предоставляет информацию из MS SQL БД.

Клиент может менять данные через WCF службу на SQL сервере.

Собственно вопрос, как правильно поддерживать данные на клиенте в актуальном состоянии?

На сколько верным решением будет каждые 5 минут по таймеру запрашивать у WCF службы
данные? Может быть есть более грамотный подход?
    


Ответы

Ответ 1



SQL Server может уведомлять WCF службу об изменениях в интересующих её таблицах. А служба, в свою очередь, уведомлять клиентов-подписчиков.

Ответ 2



По молодости была такая ошибка, при старте программы закачивал много данных с БД, потом написал обёртки к коллекциям, которые эти множества синхронизировали. При старте программа долго грузилась и было много ещё каких косяков. Согласен с @AdamSkywalker всё зависит от бизнес требований. Есть альтернативный подход. Загружать данные под конкретную операцию, к примеру нужно найти договор, не нужно загружать все 100500 договоров. А потом скролить и искать нужный договор. Это неправильно с точки зрения UX. Пользователь все равно в один момент времени не видит 100500 договоров. Загрузить 10 последних договоров и показать их пользователю. Он не нашел, ввел критерии поиска (фильтр + сортировка) и под этот фильтр запрашивается обозримое пользователем количество договоров, после того как он выбрал договор, всё это список не нужен, он выбрасывается из памяти.

Защита игры от взлома

#разработка_игр #клиент_сервер #защита


Никогда не разрабатывал игры, интересует такой вопрос, допустим есть клиент игры
в котором есть персонаж "лучник" который стреляет со скоростью 1 выстрел в 1 секунду,
если с помощью программы(например hlapex) поймать пакет который отвечает за выстрел,
и отсылать его каждые 0.1 то лучник получается будет делать 10 выстрелов в 1 секунду?
То есть на сервере нужно проверять когда был последний выстрел и если следующий выстрел
слишком быстро произошел, то блокировать этот выстрел? Или я что-то не понимаю и выстрелы
не отправляются? Вообщем может кто-то объяснить?
    


Ответы

Ответ 1



Все верно. Учитывай время между запросами. Блокируй если "выстрелы" приходят при меньшем таймауте чем разрешено.

Ответ 2



Насколько я знаю, хорошей практикой считается не отправка на сервер пакета с действием как например "Выстрел", а отправка пакета "Начал стрельбу" по нажатию клавиши и "Закончил стрельбу" по отпусканию клавиши. Скорость атаки, количество выстрелов и всё остальное при этом будет считаться на сервере, пока идёт стрельба. Как минимум такой подход защитит от ситуации, описанной в вашем вопросе.

пятница, 24 января 2020 г.

Не отправляются данные с клиента (андроид) на сервер (java pc)

#java #android #сокет #клиент_сервер


Доброе утро.

Есть клиент на андроиде, с него должна отправиться строка на сервер.
Запускаю клиент на реальном устройстве.

Вот код клиента:

public class Client extends Thread {

private boolean running = false;
private static Socket s = null;
private String ip = "тут мой ip";
private int port = 80;
private String data;
static DataInputStream din = null;
static DataOutputStream dout = null;

public Client(String name, int score){
    data = name + " " + score;
}

public void setRunning(boolean b){running = b;}

@Override
public void run() {
    while (running) {
        try {
            s = new Socket(ip, port);
            dout = new DataOutputStream(s.getOutputStream());
            din = new DataInputStream(s.getInputStream());
            dout.writeUTF(data);
        } catch (Exception ex) {}
    }
}


}

Все это действо должно отработать в другом классе, вот в этом методе:

private void sendData(String name, int score){
    client = new Client(name, score);
    client.setRunning(true);
    client.start();
}


Код сервера:

public class Server {


static ServerSocket ss;
static Socket s;
static DataInputStream din;
static DataOutputStream dout;

static String data = "";

public static void main(String[] args){
    try{
        System.out.println("Сервер запущен\n");
        ss = new ServerSocket(80);
        s = ss.accept();

        din = new DataInputStream(s.getInputStream());
        dout = new DataOutputStream(s.getOutputStream());

        while(true){
            data = din.readUTF();
            System.out.println("Score: " + data);
        }

    } catch(Exception ex){ex.printStackTrace();}
    System.out.println("Сервер остановлен");
}


}

Wi-fi на устройстве включил, ip точно мой, все по-идее должно работать.
Клиент в отдельном потоке, не понимаю тогда в чем дело.
Подскажите, пожалуйста.
    


Ответы

Ответ 1



На стороне клиента: Client.java: import java.util.*; import java.net.*; import java.io.*; public class Client extends Thread { //Все null,false,0 по умолчанию. Можно не писать. private boolean running; private Socket s; private String ip = "192.168.1.4"; private int port = 1234; static DataInputStream din; static DataOutputStream dout; public void setRunning(boolean b){running = b;} @Override public void run() { try { s = new Socket(ip, port); dout = new DataOutputStream(s.getOutputStream()); din = new DataInputStream(s.getInputStream()); while (running); } catch (Exception ex) { ex.printStackTrace(); } finally { close(); } } public boolean isConnected() { return s!=null&&s.isConnected(); } public void sendMessage(String message) { if(dout!=null&&running) { try { dout.writeUTF(message); dout.flush(); } catch(Exception ex) { running = false; } } } public void close() { if(din!=null) try{din.close();}catch(IOException io){} if(dout!=null) try{dout.close();}catch(IOException io){} if(s!=null) try{s.close();}catch(IOException io){} } } Вызов класса: Client clt = new Client(); clt.setRunning(true); clt.start(); while(!clt.isConnected()); clt.sendMessage("Hello"); clt.sendMessage(", World!"); clt.close(); Манифест: На стороне сервера: Server.java: static ServerSocket ss; static Socket s; static DataInputStream din; static DataOutputStream dout; static String data = ""; public static void main(String[] args){ try{ System.out.println("Сервер запущен\n"); ss = new ServerSocket(1234); s = ss.accept(); din = new DataInputStream(s.getInputStream()); dout = new DataOutputStream(s.getOutputStream()); while((data = din.readUTF())!=null){ System.out.println("Score: " + data); } } catch(Exception ex){ ex.printStackTrace(); } finally { if(dout!=null) try{dout.close();}catch(IOException io){} if(din!=null) try{din.close();}catch(IOException io){} if(s!=null) try{s.close();}catch(IOException io){} if(ss!=null) try{ss.close();} catch(IOException io){} } System.out.println("Сервер остановлен"); }

Android Video chat and server

#java #android #клиент_сервер


Я хочу написать что-то типо видеочата между несколькими Android телефонами.При этом
чтобы видеопоток шел напрямую между телефонами(Клиентами), а сервер (PC) лишь связывал
их между собой. Нужно это чтобы не создавать нагрузку на сервер. Возможна ли такая
схема вообще? Я честно сильно плаваю в этой теме и не знаю точно как работает передача
данных. При этом все API что я нагуглил предлагают писать подобное на их платформах
без участия сервера.Подскажите пожалуйста в какую сторону копать и какими API можно
было бы воспользоваться для этого.
    


Ответы

Ответ 1



Не уверен точно, но я бы посмотрел в сторону сокетов. Возможно по уроку ниже можно будет приспособить сокеты для видеопотока. Передача данных по сети при помощи socket при разработке android приложения

четверг, 23 января 2020 г.

создание удаленного сервера и подключение к нему через сокеты на java

#java #клиент_сервер


нашел вариант реализации клиент-серверного взаимодействия посредством UDP на java.
Сервер:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;


public class Server
{
    public static void main(String args[])
    {
    try
    {
        //Создаем сокет 
        DatagramSocket sock = new DatagramSocket(7000);

        //буфер для получения входящих данных
        byte[] buffer = new byte[65536];
        DatagramPacket incoming = new DatagramPacket(buffer, buffer.length);

        System.out.println("Ожидаем данные...");

        while(true)
        {
            //Получаем данные
            sock.receive(incoming);
            byte[] data = incoming.getData();
            String s = new String(data, 0, incoming.getLength());

            System.out.println("Сервер получил: " + s);

            //Отправляем данные клиенту
            DatagramPacket dp = new DatagramPacket(s.getBytes() ,               
                         s.getBytes().length , incoming.getAddress() , incoming.getPort());
            sock.send(dp);
        }
    }

    catch(IOException e)
    {
        System.err.println("IOException " + e);
    }
}
}


Клиент:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;


public class Example2
{
public static void main(String args[])
{
    DatagramSocket sock = null;

    BufferedReader cin = new BufferedReader(new InputStreamReader(System.in));

    try
    {
        sock = new DatagramSocket();

        while(true)
        {
            //Ожидаем ввод сообщения серверу
            System.out.println("Введите сообщение серверу: ");
            String s = (String)cin.readLine();
            byte[] b = s.getBytes();

            //Отправляем сообщение
            DatagramPacket  dp = new DatagramPacket(b , b.length , InetAddress.getByName("localhost")
, 7000);
            sock.send(dp);

            //буфер для получения входящих данных
            byte[] buffer = new byte[65536];
            DatagramPacket reply = new DatagramPacket(buffer, buffer.length);

            //Получаем данные
            sock.receive(reply);
            byte[] data = reply.getData();
            s = new String(data, 0, reply.getLength());

            System.out.println("Сервер: " + reply.getAddress().getHostAddress() +
", порт: " + reply.getPort() + ", получил: " + s);
        }
    }catch(IOException e)
    {
        System.err.println("IOException " + e);
    }
}

}


Проблема в том,что здесь взаимодействие идет через localhost и работает в рамках
одного устройства...я уже несколько дней потратил на то,чтобы понять что туда передать
вместо localhost,чтобы можно было запустить сервер на одном устройстве,А клиент на
абсолютно другом,подключенному к другой сети,пробовал и local ip пихать и ip, который
выдавали различные сайты...все не работает...подскажите пожалуйста
UPD:покопавшись,я наткнулся на такую вещь как NAT и то,что я не подключаюсь напрямую
к интернету,так что собственно как можно это обойти?
    


Ответы

Ответ 1



решил данный вопрос и решил поделиться,мало ли кого-то на что-то натолкнет... как сказал @Victor мой ip из вне был недоступен,так роутер предоставлял единый внешний ip для всех подключенных устройств,а мой ip был внутренним,не буду особо расписывать данный момент,т.к. могу что-то сказать не правильно(просто загуглите NAT). решил проблему подключением к интернету не через роутер,а напрямую воткнув кабель в ноутбук,таким образом я напрямую(!) подключился к интернету и ip моего ноутбука стал доступен из вне,что и позволило подключиться к моему серверу человеку из другого города=) свой ip можно узнать вбив ipconfig в командную строку(для Windows, для Unix не знаю) или проверив его на одном из множества сайтов. Если они совпадают,значит вы напрямую подключены к интернету и можно смело указывать данный ip вместо localhost. Если что-то написано не правильно-дополните в комментариях.

Ответ 2



Ну, собственно, подключение будет идти по вашему ip (локальному, или внешнему), никакой магии в этом нет. Просто вместо localhost подставляете ip-адрес вашего сервера(например 192.168.1.30) и радуетесь жизни. другое дело, если у вас нет внешнего ip-адреса, например у вас локальная сеть предприятия. В таком случае достучаться до вашего ip из вне будет весьма проблемно, и есть повод задуматься об отдельном сервере для этого дела. В коде проблем никаких нет. При общении в пределах локальной сети проблем быть так же не должно. Если же вам нужно настроить ваш роутер\сервер для доступа из вне, то увы, это не java, а настройки сети.

вторник, 7 января 2020 г.

Клиент -android, сервер -java app

#android #сокет #клиент_сервер


Здравствуйте, помогите пожалуйста! Есть Клиент под Android и сервер на java на pc
- когда запускаешь с эмулятора - все работает - сообщения передаются. Когда запускаешь
приложение на android устройстве - при нажатии на кнопку отправить всё вылетает.
Очень нужна ваша помощь.

Код Клиента:

package com.example.client;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import com.example.client.R;
import android.app.Activity;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;    
public class MainActivity extends Activity {

private Socket client;
private PrintWriter printwriter;
private EditText textField;
private Button button;
private String messsage;
String ip="192.168.0.80";
int port=80;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);
textField = (EditText) findViewById(R.id.textout); 
button = (Button) findViewById(R.id.send);

button.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {

messsage = textField.getText().toString(); 
Socket client =null;
textField.setText("");      
DataOutputStream dataOutputStream= null;
DataInputStream dataInputStream = null;

try {

 client = new Socket("192.168.0.80", 80);
 client.setSoTimeout(100);
 dataOutputStream = new DataOutputStream(client.getOutputStream());
 dataInputStream = new DataInputStream(client.getInputStream());
 dataOutputStream.writeUTF(messsage);

} catch (UnknownHostException e) {
 e.printStackTrace();
} catch (IOException e) {
    System.out.println("Got an IOException: " + e.getMessage());
}
}
});
}
}

    


Ответы

Ответ 1



Вы производите коннект с сервером в главном потоке, на реальном устройстве в новых версиях Android SDK это выкидывает исключение, а на эмуляторе работает. Вам нужно создать поток Thread или Runnable и вынести всю логику коннекта и связи на этот поток. Обновление Вот этот код внесите в run(): client = new Socket("192.168.0.80", 80); client.setSoTimeout(100); dataOutputStream = new DataOutputStream(client.getOutputStream()); dataInputStream = new DataInputStream(client.getInputStream()); dataOutputStream.writeUTF(messsage);

Ответ 2



Почитайте следующие статьи Отзывчивое Android-приложение или 1001 способ загрузить картинку Процессы и потоки в Android: пишем AsyncTask правильно «Правильный» html парсинг

суббота, 4 января 2020 г.

Как реализовать обновления сервера без отключения текущих пользователей?

#клиент_сервер #обновления


Я разрабатываю клиент и сервер на C++. Мне нужно реализовать возможность обновления
сервера без вреда пользователям. Проблема в том, что я не должен отключать пользователей
с выходом новой версии сервера, из-за его перезапуска.
Пока я додумался только до такого решения, чтобы запускать новую версию сервера с
новым портом, а старые не закрывать, пока ими кто-то пользуется. Пользователь сначала
соединяется с маленьким сервером, который отправляет ему порт основного сервера. (Или
для его версии клиента, или просит обновиться, а потом присылает порт последней версии).



Добавлю что взаимодействия между пользвателями нет. Пользователь обращается к серверу
за специальными расчётами.
    


Ответы

Ответ 1



Странное изобретение велосипеда на ровном месте. Как будто, у вас соединение по сети - вечное. В век мобильных устройств и прочего, гораздо проще заложится на корректную переустановку соединенея, чем изобретать какой-то ужас. Чем отличается ситуации - "соединение с клиентом пропало", "сервер упал и его подняли (думаете, этого не будет?)", "сервер перезапустили"? С точки зрения клиентов - ничем. Так что и механизм должен быть один - корректное переподключение.

Ответ 2



Дополнение к варианту 2 ответа от @Mike Клиенты общаются с сервером не напрямую, а через некий простой фронтэнд сервер, который работает фактически в режиме прокси В *nix (вероятно и в Mac тоже) возможна реализация эффективного proxy, который передает другому процессу на том же хосте полученное соединение (открытый дескриптор) по UNIX DOMAIN или datagram сокету, а не транслирует в обе стороны все данные. Для этого (File Descriptor Passing) используется системный вызов sendmsg. Подробности можно посмотреть здесь или по запросу в гугле unix socket magic sendmsg. Как это можно использовать в Вашем случае imho достаточно очевидно.

Ответ 3



Думаю можно попробовать примерно такой алгоритм. У сервера есть несколько основных портов, на которых он может работать. При запуске он пытается занять первый в списке порт, если ему это не удалось, т.к. порт занят другим сервером, он занимает следующий свободный порт. При этом он знает, что запущена старая копия. Он открывает соединение со старой копией, как это обычно делает клиент, и сообщает что он новый сервер. Старый сервер убеждается, что запрос пришел именно от его новой копии (какой нибудь криптографией или просто увидев, что он с 127.0.0.1). После чего он рассылает всем текущим клиентам команду соединятся с новой копией на новом порту. Когда все клиенты перейдут (отключатся от него) или по определенному таймауту он завершается. Новая копия, после завершения старой, может занять опять свой обычный порт и попросить клиентов занять опять обычный порт. Или не просить, они сами со временем перейдут. Вариант 2: Клиенты общаются с сервером не напрямую, а через некий простой фронтэнд сервер, который работает фактически в режиме прокси. Это фронтэнд через unix сокеты или сетевые сокеты передает запросы на основной бакэнд сервер и возвращает его ответы клиентам. Он же может служить балансером нагрузки и распределять запросы на разные бакэнд сервера. Соответственно обрыв коннектов у клиентов может быть только при перезапуске фронтэнда, но т.к. никакой бизнес-логики на нем не будет, то после первичной отладки выпускать его новые версии скорее всего не понадобится. Вариант 3: Все как вы и сказали в вопросе, только "маленький сервер" для сообщения текущего номера порта основного сервера изобретать не нужно. Он уже давно изобретен, называется DNS. В свою доменную зону добавляете SRV запись примерно следующего содержания: _myserv._tcp 10 IN SRV 0 5 1234 myserver.example.com. ; ^ ^ ; | Порт на котором сейчас служба - TTL записи. 10 секунд, т.е. DNS сервера не будут ее держать в кеше более 10 секунд Вам конечно надо будет научить свое клиентское приложение использовать эти записи, помимо A записей, указывающих IP. Запись можно обновлять автоматически при запуске нового сервера через механизм ddns.

Ответ 4



Нужно решать вопрос не о сохранении "живым" соединения с пользователем, а о восстановлении в памяти пользовательской сессии при перезапуске процесса сервера. Вы можете держать эти данные в памяти, общей для двух процессов. Но второй процесс - это совершенно тупоголовый бинарник, который только держит дескриптор. Перезапущенный сервер должен находить этот бинарник и "возвращать себе" память.

вторник, 31 декабря 2019 г.

Клиент, который находит нужные сервисы

#c_sharp #net #клиент_сервер


Как создаются клиенты, которые могут опросить сеть и найти нужные экземпляры служб?

Например, MS Managment Studio может опросить сеть и найти все экземпляры MS SQL.
При этом никакие IP заранее неизвестны.

С помощью чего\какого алгоритма это достигается?
    


Ответы

Ответ 1



Самый простой вариант - UDP broadcast. Предусловия: на искомых сервисах запущен UdpListener на известном и фиксированном порту. сервисы располагаются внутри локальной сети или настроена маршрутизация, позволяющая работать с сервисом, не покидая пределы адресного пространства локальной сети. Алгоритм: клиент отправляет по UDP широковещательный запрос (broadcast) на порт, который должны слушать сервисы, если они есть в сети и находятся в рабочем состоянии. сервис, услышав такой запрос, получает из запроса контактные данные клиента, встречным запросом, передает свои контактные данные и продолжает слушать, вдруг еще клиент появится. Недостатки: Работает только в локальных сетях, т.к. в глобальных сетях, а часто и в сетях уровня предприятия (объединяющих более мелкие локальные сети), широковещательные запросы запрещены на маршрутизаторах, с целью уменьшить количество мусорного трафика и разгрузить сетевое оборудование, которому, обычно, и так есть чем заняться. Если сервис не слушает UDP Дальнейшие способы, с оговорками, могут применяться и в глобальных сетях. Сервис имеет известный порт по-умолчанию В этом случае можно выполнить опрос известного диапазона адресов по данному порту, иными словами, просто попробовать подключиться. Недостатки: медленно, очень медленно, если большая часть диапазона адресов не занята какими-либо сетевыми устройствами, умеющими сказать, что порт закрыт и сервиса тут нет. Но можно немного облегчить себе жизнь выполняя множество запросов асинхронно, т.к. все запросы по своей сути ожидание ответа от хоста, если он там есть или обрыва по таймауту, если на адресе никого нет. Про сервис не известно ничего, кроме возможных(!) параметров подключения Случай практически безнадежный, но, в некоторых случаях, решаемый. Аналогично предыдущему варианту, придется пробежаться, например ping-ом, по всему целевому диапазону адресов, чтобы определить живые хосты. После этого на живых хостах нужно пробежаться по диапазону возможных портов (в худшем случае по всем) и попытаться подключиться. Такой вариант можно применять только в самом крайнем случае, т.к. он требует массу времени, забивает сеть, на него неадекватно реагируют файерволы (и админы) и т.д. Кроме того, хост может попросту игнорировать попытки подключения к запрещенным портам , имитируя свое отсутствие, что также отрицательно скажется на времени опроса. В общем случае применение не рекомендуется.

пятница, 27 декабря 2019 г.

Сервер очередей под задачу

#клиент_сервер #очередь #rabbitmq #backgroundworker #gearman


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

Я почитал, что для этого в принципе подходит gearman, но хотелось бы услышать еще
и ваши мнения. Также читал про популярный rabbitMq, но не нагуглил в нем возможности
задавать несколько воркеров.

Язык программирования, в принципе, не важен, главное чтоб многопоточность поддерживал
(многоядерную).
    


Ответы

Ответ 1



RabbitMQ позволит тебе подключить к одной очереди несколько consumer-ов (см. http://www.rabbitmq.com/tutorials/tutorial-two-python.html Fair Dispatch). По поводу динамических консьюмеров - тут твое приложение само должно решать когда их запускать и как их выключать. Можешь запустить кол-во консьюмеров равное кол-ву ядер на машине и потом собирать данные. А твоя задача напоминает реализацию MapReduce. Может тебе имеет смысл взглянуть на Hadoop? Если все же хочешь написать сам, то по поводу языка можно выбрать Erlang/OTP (на нем написан RabbitMQ). Работа с потоками там построена очень хорошо и объединить несколько машин в кластер, с шарингом потоков, не составит труда. Твое приложение не будет думать о том, где и что выполняется, а просто ждать завершения всех воркеров и вернет результат. Но сломать мозг придется, прежде чем написать функциональный код :)

Ответ 2



Из того, что уже советовали - RabbitMQ. Если нагрузки маленькие и вам необязательна гарантируемость доставки, бурите его. В случае с Rabbit смиритесь с тем, что сообщения могут потеряться, смиритесь с тем, что при больших нагрузках кластер начнёт отказывать, смиритесь с тем, что при разделении сети будут проблемы. Можно ещё взять Apache Kafka. Там с этим лучше, но его настраивать очень сложно, чтоб он хорошо работал. Для вашей же задачи подойдёт Hadoop или Spark. Если хоститесь на амазоне, то с их лямбдами вроде как подобное можно реализовать.

среда, 25 декабря 2019 г.

Поиск компьютера в сети

#сеть #net #клиент_сервер #c_sharp


Здравствуйте!) Имеется программа по типу клиент-сервер, но она может выступать как
клиент и как сервер) Т.е. имеется группа компьютеров соединенных в сеть по Wifi, на
каждом стоит эта программа. На одном из компьютере в программе ставиться галочка, что
я сервер, значит все остальные должны осуществить его поиск и присоединиться к нему
- клиенты. Далее через определенное время сервер начинает рассылать сообщения по своему
требованию, а также по требованию клиентов. Как найти сервер?
Иначе же зная заранее имя компьютера-сервера можно подключиться к нему, но как узнать
его IP в сети автоматически? 
Да, можно конечно же через ipconfig узнать ip, указать его в клиенте и подключится)
Но как это сделать автоматически?
Спасибо.    


Ответы

Ответ 1



В локальном сегменте Ethernet сети это делается посылкой bradcast udp пакета (всем на заданный порт) на который сервер отвечает конкретно отправителю (получив этот пакет из него узнаем IP сервера). Для нелокальной подсети этот метод работает только если на роутерах разрешен "внешний" broadcast (обычно админы закрывают его). Будет ли bradcast udp работать в WiFi не знаю (но попробуйте искать в этом направлении).

четверг, 19 декабря 2019 г.

C++: кросплатформенный TCP клиент-сервер

#cpp #tcp_ip #клиент_сервер


Гуглил на тему tcp клиент-сервера, но выдает либо через WinAPI, либо через socket-ы
Linux.
Неужели за столько лет не появилось нормального кроссплатформенного решения в виде
приложения к стандартной библиотеке?
Прошу прояснить ситуацию
    


Ответы

Ответ 1



Добрый день! Нет, сети в стандарте С++, по-моему, до сих пор не появились. Поэтому ищем дополнительные, сторонние библиотеки. Используйте boost::asio или что-то подобное

Ответ 2



Если сервер не высоконагруженный, то ничего искать не нужно. Все, что касается сети и под Win и под Linux будет будет с бОльшего вполне кроссплатформенно. Ну да, разные header файлы будут. Ну и под Win придется библиотеку подключить дополнительно. Но это меньшее из зол (имеется ввиду чем тянуть еще буст и т.п.). Если же нужен сильный сервер, тогда, на мой взгляд, лучше вообще его писать под ту ось, на которой он и будет работать, а не придумывать себе сказку, что "сейчас я сделаю кроссплатформенный сервер, нужный всем и на всех осях и на все случаи жизни, и этот сервер будет держать 100500 соединений". Что касается клиента, то здесь тем более нет проблем. Но это все относительно вопроса ( а там только про сеть упоминалось ).

Ответ 3



Посмотри в сторону Qt. Они сейчас выросли в разы. Я бы делал на нем. Так же можно использовать Node.js , он прекрасно работает и под вин и под линукс. Php тоже самое, есть интепретатор под виндоус. Код менять не придется.

Ответ 4



Я щупал Qt и asio. Asio (в standalone-версии) - самый лёгкий вариант в плане размера бинарников и скорости исполнения, Qt почти не отстаёт по скорости, но библиотеки намного тяжелее (Qt5Core - 5+Мб, Qt5Network - 1.5Мб, тогда как бинарники клиента и сервера через asio были намного меньше 100 кб), но лучше документирован. Для asio почти вся документация идёт в варианте boost::asio, чтобы разобраться со standalone-версией пришлось денёк покопаться. Если решение в основном планируется на STL, я бы использовал asio. Если же в проекте Qt уже используется, QTcpServer и QTcpSocket сильно проект не утяжелят.