Форум » » C# и Websocket. Нужна помощь. » Ответить

C# и Websocket. Нужна помощь.

Paul_T: В C# пока полный 0, но изучать надо... Решил написать модуль для управления LG телевизора, работающий на Webos. Коммуникация ТВ осуществляется по Websocket на порт 3000. В библиотеках SIMPL# есть класс WebSocketClient, но мне показалось он несколько скуднее на методы, чем такой-же клас в библиотеках .NET. Ну да ладно, как я понимаю, сторонние библиотеки не прокатят и нужно пользоваться только теми, что описаны в SIMPL# (ну, кроме System, видимо). Написал клиентскую часть, соединение с сервером, получение клиентского ключа, сохранение ключа в файле, реализовал несколько команд управления. Работает! громкостью управляет, это уже хорошо, можно развивать дальше, но оказалось все не так просто. После простоя в минуту-две (отсутствие посылок клиент-сервер) сервер перестает отвечать на запросы, при этом метот Send(...) возвращает код WEBSOCKET_CLIENT_SUCCESS. Помогает только переподключение, т.е. нужно разорвать соединение и подключиться заново. За основу своего модуля брал простейший модуль написанный на JS, все сообщения соответствуют этому модулю. JS модуль работает в браузере без ограничения времени, поэтому предположу, что проблема не на стороне телеыизора. Но как ее найти, не понимаю... Может нужно делать асинхронное соединение? Но как это сделать методами SIMPL# так пока и не понял. Может кто сталкивался? Спасибо за любую помощь! PS. Еще заметил, что метод Read() выполняется бесконечно долго при отсутствии ответа от сервера. Может он имеет какие либо таймауты? Но я этого не нашел.

Ответов - 63, стр: 1 2 3 4 All

olegny: А 100% все время держится? Надо несколько раз проверить в течении какого-то времени (минуты-другой), ибо может угомониться в конце концов. А без Simpl+ проги все нормально с CPULOAD? Хорошо было бы от вас получить оную апликуху, чтобы на тестовой железке проверить, а то мы тут с чем-то подобным сейчас разбираемся... )) Тем более, что и соединение с телеком устанавливать не надо для этого! Вы к этому асинхронному программированию относитесь как к священной корове, хотя там ничего особенного-то и нет... Делаете прямо вот так: WebSocketClient ws = new WebSocketClient(); ws.ReceiveCallBack = ((data, datalen, opcode, error) => { //DO WHATEVER YOU WANT HERE! return (int)WebSocketClient.WEBSOCKET_RESULT_CODES.WEBSOCKET_CLIENT_SUCCESS; }); Параметры оной лямбда-функции соответствуют параметрам и описанию делегата: // Summary: // Callback delegate for asynchronous data receive method for user application // // Parameters: // data: // received data // // datalen: // length of received data // // opcode: // opcode of packet type received // // error: // error code returned on callback // // Returns: // return WEBSOCKET_CLIENT_SUCCESS if successful public delegate int WebSocketClientAsyncReceiveCallback(byte[] data, uint datalen, WebSocketClient.WEBSOCKET_PACKET_TYPES opcode, WebSocketClient.WEBSOCKET_RESULT_CODES error); Потом просто зовете ReceiveAsync и забываете про него пока оный не позовет ваш callback, заданный выше, с принятыми данными. Аналогично поступаете и с другими Async методами в соответсвии с их делегатами, но сдается мне, что вам достаточно будет только асинхронного Receive.

Paul_T: olegny пишет: Да. 100% всегда. Но иной раз загрузишь и все работает до какого-то момента. Я еще толком не копался. Есть мысли. Надо попробовать. Проект скину на файлообменник. Но там пока лютый бардак... За пример спасибо. С остальным разберусь )

Viacheslav Alekseev: Где-то у вас там есть бесконечный цикл, в который программа сваливается сразу или через какое-то время. Отсюда и CPU Load 100%. Нередко они возникают в циклах, отвечающих за чтение или переподключение, когда Receive(), например, гоняется по кругу или Connect(). Или что-то подобное. Тут надо весь код целиком видеть.


olegny: Так, вроде, сказано было, что еще до подключения к websocket хотя все может быть конечно...

Paul_T: Все верно. В Simpl+ вкралась ошибка в цикле while. Заморочился на C# и сразу не увидел очевидного, что даже не касается основной программы.

olegny: Ну так неинтересно! Я-то думал это типа "Слушай. Обидно, клянусь! Обидно, ну! Ничего не сделал да— только вошёл..." ))

Paul_T: olegny пишет: Да, у нас так всегда ))) Сделал парсинг ответа с массивом приложений ТВ. Вчера работал, сегодня нет ))) создаю обьект и список обьектов типа App public class App { public string id { get; set; } public string icon { get; set; } public string title { get; set; } } public List<App> appList = new List<App>(); Далее выделяю из ответа "полезную нагрузку" - массив JToken. Далее пытаюсь заполнить список обьектов App значениями из массива JToken var app_array = JObject.Parse(rec_string)["payload"]["launchPoints"]; foreach (JObject item in app_array) { appList.Add(JsonConvert.DeserializeObject<App>(item.ToString())); } Так вот "вчера" работало... А сегодня получаю исключениt (FormatException), что не может преобразовать обьект в тот, что мне нужен... Как обычно, ничего не делал, оно само ))). Дописал просто такую-же часть для списка каналов... и все рухнуло ))) rec_string - строка ответа от сервера. Парсинг в app_array проходит нормально. А вот преобразование в .NET обьект нет... Все поля соответствуют... Продолжаю наблюдение ))) UPD Написал все то-же самое... нажал "Перестроить решение", опять заработало...

Paul_T: Как обещал, выложил все на гугл диск: Ну, если, вдруг, кому интересно. Сильно не пинайте ))). Выглядит пока коряво... Что сделал: - Включается по WOL из Simpl+. (но, если в S+ поставить директиву #ENCODING_UTF16, то перестает. Но включать можно и из Simpl) - Соединяется с сервером, проверяет ключ в файле. Если файла нет или ключ не соответствует, то запрашивается новый и пишется в файл - Реализованы основные команды - навигационные кнопки, цифровые кнопки 0-9, входы, кромкость +/-, каналы +/- . - Пробовал реализовать мышку, но получается коряво. Но особой необходимости в ней нет. - Можно читать список приложений и каналов. Но массивы этих данных пока не передавал в Simpl+ - Громкость можно задавать аналоговым значением, но пока без фидбека. Что нужно сделать: - Описать обработку исключений в C# - Отслеживать состояние ТВ пингом или по питанию на USB - Проработать логику подключения/отключения в зависимости от состояния ТВ (вкл/выкл) - Динамические списки приложений и каналов? - Фидбэк состояния громкости - ...

Paul_T: Забросил на некоторое время модуль, и, вот вернувшись, обнаружил новую ошибку... При определенном простое возникает исключение NullReferenceException. Если программа работает и постоянно шлет/принимает данные, то все работает хорошо. Но после минуты-две простоя "забывает" что-то ))) Если я не ошибасб, то исключение возникает при попытки вызова метода "Receive". Но пока не понимаю, что там может быть не так. WebSocketClient.WEBSOCKET_PACKET_TYPES type; WebSocketClient.WEBSOCKET_RESULT_CODES receive_result = Client.Receive(out receivedata, out type); Лог: 16. Exception 'Data Abort' (0x4): Thread-Id=08b708ca(pth=95111cb0), Proc-Id=0952b5c6(pprc=95137268) 'splusmanagerapp.exe', VM-active=0952b5c6(pprc=95137268) 'splusmanagerapp.exe' 17. PC=0032c9e4(???+0x0032c9e4) RA=0032c9d0(???+0x0032c9d0) SP=02a6fb0c, BVA=00000000 18. Error: splusmanagerapp.exe [App 1] # 2019-06-10 10:10:07 # Module S-3 : LGTV_WebOs_Client at line 167: Unhandled Exception: System.NullReferenceException: NullReferenceException at WebSocketClientLibrary.SimplWebSocketClient.GetResponse() at WebSocketClientLibrary.SimplWebSocketClient.SendCommand(String t 19. Error: splusmanagerapp.exe [App 1] # 2019-06-10 10:10:07 # oSend) at UserModule_LGTV_WEBOS_CLIENT.UserModuleClass_LGTV_WEBOS_CLIENT.VOLUMEDOWN_OnPush_7(Object __EventInfo__) at Amib.Threading.Internal.WorkItem.n() at Amib.Threading.Internal.WorkItem.Execute() at Amib.Threading.SmartThreadPool.f(Wo 20. Error: splusmanagerapp.exe [App 1] # 2019-06-10 10:10:07 # rkItem A_0) at Amib.Threading.SmartThreadPool.r()

DmitriiP: оберните всё что внутри GetResponse в try/catch public void GetResponse() { try{ то что там сейчас } catch(e) { CrestronConsole.Print("Error GetResponse: " +e.toString()); } }

Paul_T: DmitriiP пишет: Сейчас попробую, может получится локализовать 'неисправность' PS Еще возникла такая задача: Телевизор отдает ссылки на иконки каналов, но проблема в том, что с панели эти URL, есстественно, не доступны, т.к. подключение к телеку выполняет контроллер. Каким образом можно транслировать эти URL в панель?

olegny: Да, надо поймать эту null ссылку на объект сначала. Хотя и без этого, 'Data Abort' наводит на грустные мысли... Надеюсь это уйдет вместе с NullReferenceException

Paul_T: olegny пишет: У меня сложилось мнение, что это из разряда PONG... Выполняется: WebSocketClient.WEBSOCKET_RESULT_CODES receive_result = Client.Receive(out receivedata, out type); receive_result возвращает положительный результат выполнения, но массив байтов receivedata похоже пустой... И, когда далее receivedata преобразуется в строку, появляется исключение... Лечится, если 'долбить' клиента постоянными send/receive. После простоя в минуту что-то 'засыпает' ))) После реконнекта опять все работает до определенного 'простоя'.

olegny: Ну это может быть, но подобный exception нельзя допускать все равно. Проверяйте тогда всё возвращаемое из Receive на null всегда... P.S. Надо сфомулировать проблему насчет PING-PONG с куском неработающего кода и я зафайлю им баг - может и починят когда-нибудь... ))

Paul_T: olegny пишет: Кстати, если обрабатывать исключения, то они все равно пишутся в Error Log. Receive в принципе не должен возвращать null. Он блокирует выполнение и ожидает данных. Откуда там null, не понимаю. Сегодня не могу никаким образом получить это Exception. Вчера обновлял весь софт Crestron, возможно с этим связано, но обновлений библиотек Simpl# нет... В Change Log к Crestron Database 78.05.002.00 написано Improved exception handling... Относится это к Simpl# или нет, не знаю. PS По поводу Ping/Pong можно попробовать, но не знаю, что писать... Его просто нет ))) P.P.S Еще я не понимаю, почему 1. Warning: ConsoleServiceCE.exe # 2019-06-11 09:55:32 # SHELL connection being closed from address 192.168.1.50. зажигает на контроллере лампу MSG. Можно как-то сделать, чтобы MSG зажигалась только от Error?

olegny: Paul_T пишет: Кстати, если обрабатывать исключения, то они все равно пишутся в Error Log. Это как это? Если это у вас в коде, вы это поймали и отфильтровали как рекомендовал выше DmitriiP, то в лог попасть ничего не должно. Другое дело если это происходит внутри метода клиента (фирмвари), то да - там они любят сами пофильтровать, запихнуть в лог и отправить (или не отправить) исключение наверх пользователю... Paul_T пишет: Receive в принципе не должен возвращать null. Мало ли кто чего не может или не должен... )) В случае внутренней ошибки очень даже может. Пролема только в том, что ошибку-то вам и не вернули. Доверяй, но проверяй! ;) Paul_T пишет: Вчера обновлял весь софт Crestron, возможно с этим связано, но обновлений библиотек Simpl# нет... В Change Log к Crestron Database 78.05.002.00 написано Improved exception handling... Относится это к Simpl# или нет, не знаю. Сложно сказать. Надо смотреть на конкретные изменения. Библиотеки Simpl# это только надводная часть айсберга. То, с чем вы работаете - чистая фирмарь в Simpl# оболочке. Paul_T пишет: По поводу Ping/Pong можно попробовать, но не знаю, что писать... Его просто нет ))) В смысле его вам не отдают наверх? )) Это да, в прошлый раз это выяснили вроде... но они должны тогда сами это поддерживать. И если в wireshark нет ответа на ping, то сие и есть баг. Paul_T пишет: Можно как-то сделать, чтобы MSG зажигалась только от Error? Наверное нет, но я попробую узнать... Проще попросить спрятать эти Warning по поводу SHELL, но это тогда со следующим релизом только... ))

Paul_T: olegny пишет: Это как это? Если это у вас в коде, вы это поймали и отфильтровали как рекомендовал выше DmitriiP, то в лог попасть ничего не должно. Другое дело если это происходит внутри метода клиента (фирмвари), то да - там они любят сами пофильтровать, запихнуть в лог и отправить (или не отправить) исключение наверх пользователю... Однако, именно так и сделал... try{ rec_string = Encoding.UTF8.GetString(receivedata, 0, receivedata.Length); } catch(Exception e) { CrestronConsole.Print("Error GetResponse: {0}", e.toString()); } В результате получил ошибку в Error логе и то-же самое в консоле... Сейчас уже сложно проверить, т.к. пока все работает без этого исключения. olegny пишет: И если в wireshark нет ответа на ping, то сие и есть баг. Нет, в Wireshark нет. Я про кусок неработающего кода... "чтобы зафайлить им баг..." Все таки никак не понимаю, что делать с иконками... Телевизор отдает URL контроллеру, но с панели я не могу забрать эти иконки. Не сказать, что это очень важно, но просто интересно, каким образом это решается. Выкачивать иконки на контроллер и оттуда отдавать панели? Так себе метод, затратный))) PS Запилил отображение списка каналов и приложений в динамическом списке.

olegny: Paul_T пишет: В результате получил ошибку в Error логе и то-же самое в консоле... Очень странно, ибо CrestronConsole.Print не дублируется в лог. Вы именно что видели там текст, содержащий "Error GetResponse:"? Paul_T пишет: Так себе метод, затратный Нормальный если другого способа нет... ;) Может кэшировать их где-нить для скорости!

Paul_T: В Errorlog было все тоже самое, что без обработки исключений, плюс CrestronConsole.Print печатал содержание обработанного исключения в консоль. Сейчас пытаюсь воспроизвести такую ситуацию, в лог пишется 18. Exception 'Data Abort' (0x4): Thread-Id=08d001d6(pth=95159c08), Proc-Id=088000f6(pprc=95144d70) 'splusmanagerapp.exe', VM-active=088000f6(pprc=95144d70) 'splusmanagerapp.exe' 19. PC=00320690(???+0x00320690) RA=00320684(???+0x00320684) SP=02a7fa7c, BVA=00000000 В консоль, собственно само исключение: System.NullReferenceException: NullReferenceException at WebSocketClientLibrary.SimplWebSocketClient.GetResponse() at WebSocketClientLibrary.SimplWebSocketClient.SendCommand(String toSend) at UserModule_LGTV_WEBOS_CLIENT.UserModuleClass_LGTV_WEBOS_CLIENT.VOLUME_OnChange_0(Object __EventInfo__) at Amib.Threading.Internal.WorkItem.n() at Amib.Threading.Internal.WorkItem.Execute() at Amib.Threading.SmartThreadPool.f(WorkItem A_0) at Amib.Threading.SmartThreadPool.r() Похоже, что все корректно. Я, все-таки, думаю, что это было связано с обновлениями, ибо ранее такой ошибки я не наблюдал, и когда опять вернулся к своей программе был удивлен ее появлению. Сейчас вопрос решился сам после очередного обновления и ошибки нет... (все валим на Crestron ))) С картинками пока не вижу другого варианта. Надо подумать, как их скопиповать на контроллер и отдать в панель... PS Сейчас при перезугрузке контроллера возникает такая ошибка: 4. Warning: LogicEngine.exe # 2019-06-13 09:26:29 # CresStore: calling redisAsyncFree while connected 5. Error: LogicEngine.exe # 2019-06-13 09:26:29 # CresStore: callback with no reply

DmitriiP: а проверить receivedata на null что мешает :)??? public void GetResponse() { byte[] receivedata; string new_ClientKey = ""; WebSocketClient.WEBSOCKET_PACKET_TYPES type; WebSocketClient.WEBSOCKET_RESULT_CODES receive_result = Client.Receive(out receivedata, out type); //Получаем ответ от сервера if (receivedata != null) { try{ string rec_string = Encoding.UTF8.GetString(receivedata, 0, receivedata.Length); CrestronConsole.Print("Received: {0}\r\n", rec_string); //много много букав catch(Exception e) { CrestronConsole.Print("Error GetResponse: {0}", e.toString()); } } } else { CrestronConsole.Print("Received: null!!!\n"); // можно ещё вывести для наглядности receive_result } } Надеюсь вы в try/catch обернули веь код а не только CrestronConsole.Print("Received: {0}\r\n", rec_string);



полная версия страницы