Diskuze: Asynchronní síťová komunikace v c#
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Zobrazeno 5 zpráv z 5.
K personalizaci obsahu a reklam, poskytování funkcí sociálních médií a analýze naší návštěvnosti využíváme soubory cookie. Informace o tom, jak náš web používáte, sdílíme se svými partnery pro sociální média, inzerci a analýzy. Partneři tyto údaje mohou zkombinovat s dalšími informacemi, které jste jim poskytli nebo které získali v důsledku toho, že používáte jejich služby.
Používáme nezbytné cookies pro fungování webu a s tvým souhlasem také analytické a marketingové cookies.
Zajišťují základní funkce, bezpečnost a služby, které sis vyžádal. Nelze je vypnout.
| Služba | Poskytovatel | Účel | Cookies a úložiště | Doba uložení |
|---|---|---|---|---|
| ITnetwork | ITnetwork | Provoz webu, relace, přihlášení a uložení nastavení cookies. | PHPSESSID, auth_token, sid, itn_consent_impression, __Host-itn_consent | Relace až 1 rok |
| Google Tag Manager | Správa značek a načítání měřicích nástrojů webu. | Žádné | Neukládá se | |
| Google Fonts | Načítání typografie webu. | Úložiště řízené poskytovatelem | Dle podmínek poskytovatele | |
| Google Hosted Libraries | Načítání potřebných knihoven a stylů webu. | Úložiště řízené poskytovatelem | Dle podmínek poskytovatele | |
| Google reCAPTCHA | Ochrana formulářů a webu před zneužitím. | _GRECAPTCHA, rc::a, rc::b, rc::c, rc::f | Relace až 180 dní | |
| YouTube | Přehrávání vloženého video obsahu. | localStorage, IndexedDB; cookies after playback interaction | Relace až trvalé úložiště | |
| Vimeo | Vimeo | Přehrávání vloženého video obsahu. | __cf_bm, _cfuvid, vuid, localStorage, IndexedDB | Relace až 2 roky |
| Facebook Login | Meta | Přihlášení pomocí účtu třetí strany. | Úložiště řízené poskytovatelem | Relace až 1 rok |
| GoPay | GoPay | Zpracování uživatelem vyžádané platby. | Úložiště řízené poskytovatelem | Dle podmínek poskytovatele |
Pomáhají nám porozumět používání webu a zlepšovat ho.
| Služba | Poskytovatel | Účel | Cookies a úložiště | Doba uložení |
|---|---|---|---|---|
| Google Analytics 4 | Měření návštěvnosti a používání webu. | _ga, _ga_* | Až 2 roky | |
| Microsoft Clarity | Microsoft | Měření návštěvnosti a používání webu. | _clck, _clsk, _cltk | Relace až 1 rok |
Slouží k měření kampaní, personalizaci reklamy a marketingové komunikaci.
| Služba | Poskytovatel | Účel | Cookies a úložiště | Doba uložení |
|---|---|---|---|---|
| Google Ads | Měření kampaní, reklama a remarketing. | _gcl_au, _gcl_ls | Relace až 90 dní | |
| Meta Pixel | Meta | Měření kampaní, reklama a remarketing. | _fbp, _fbc, localStorage | Až 90 dní |
| Sklik | Seznam.cz | Měření kampaní, reklama a remarketing. | retargeting, sid, szn:* | Relace až trvalé úložiště |
| LinkedIn Insight | Měření kampaní, reklama a remarketing. | bcookie, li_gc, lidc, __cf_bm | Relace až 1 rok | |
| Ecomail | Ecomail.cz | Měření kampaní, reklama a remarketing. | ecmid, Úložiště řízené poskytovatelem | Dle podmínek poskytovatele |
| Atribuce kampaní ITnetwork | ITnetwork | Přiřazení návštěvy a objednávky ke kampani. | campaign_clid[*], user_session_context | Až 1 rok |
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Což takhle síťovou komunikaci jako takovou provádět v samostatném vlákně?
Fakt, že posíláš celý objekt serializovaný vypovídá o chybném návrhu protokolu. Většinou se data mapují do/z datagramu a většinou si v případě takové potřeby dopíšeš do hlavičky velikost paketu v bytech. Pak víš, že určitě nemá smysl paket číst dokud se nenačetlo pole s hodnotou a pokud se načetlo, tak má smysl paket číst jen pokud je skutečně tak velký jako je v poli uvedeno. U síťových aplikací je dobré (možná nutnost) obsluhovat komunikaci v odděleném vlákně a třeba pomocí událostí exportovat data do aplikace, tím se ti vyřeší zasekávání. Nenapsal jsi, jestli stavíš nad UDP nebo TCP (nebo něčem jiném?), pak by se dala postavit konstruktivnější rada.
Aha a já jsem si myslel, jak je to elegantní, když budu každý příkaz
posílat v serializovaném objektu a nebudu muset parsovat řetězec... navíc
bych chtěl časem posílat i krátké hlasové zprávy. Chtěl bych tedy
poprosit o trochu detailnější radu. Pracuju s TCP, pro server každého tcp
klienta jsem udělal oddělené vlákno. Příkazy ukládám do instance níže
uvedené třídy, kterou pak serializuji a ukládám do NetworkStreamu. Příkaz
je v řetězci, argumenty v kolekci typu Object. Čtení probíhá tak, že v
odděleném vlákně ve smyčce zkouším deserializovat objekt rovnou z
NetworkStreamu a jednotlivé argumenty pak chci přetypovat podle toho, který
příkaz přišel. Je to podle návodu z netu, ale nechápu, jak BinaryFormatter
pozná, že už objekt dorazil celý. Zkoušel jsem takto posílat textové
zprávy a šlo to.
;
using System;
using System.Collections.Generic;
namespace Ludo
{
public enum MessageType
{
Test,
Info,
GameAction,
PlayerAction,
Error
}
[Serializable]
public class NetMessage
{
#region fields
private List<Object> _args;
#endregion
#region constructors
public NetMessage(string command) : this(MessageType.Info, command, null, null)
{
}
public NetMessage(MessageType type, string command, List<object> args) : this(type, command, null, null)
{
//Copy the list
_args = new List<object>(args);
}
public NetMessage(MessageType type, string command, object arg1, object arg2 = null)
{
Type = type;
Command = command;
if (string.IsNullOrEmpty(Command) || string.IsNullOrEmpty(arg2))
throw new ArgumentException(nameof(this));
_args = new List<object>();
_args.Add(arg1);
if (arg2 != null)
_args.Add(arg2);
}
#endregion
#region properties
public List<object> Args { get => _args; }
public string Command { get; private set; }
public MessageType Type { get; private set; }
#endregion
}
}
Právě výhoda řešení "udělej si formát zpráv/komunikační protokol sám" spočívá v tom, že vždy víš, kolik bajtů chceš přečíst. Obvyklý návrh je takový, že zpráva se skládá z hlavičky pevné délky (např. vždy 32 bajtů) a nepovinného těla, jehož délka je uvedena v hlavičce.
Přečtení jedné zprávy pak znamená přečtení hlavičky, získání délky těla a přečtení těla. Nevýhoda samozřejmě spočívá v tom, že si musíš ta přijatá data naparsovat, na druhou stranu budeš asi efektivnější co se týče množství přenesených dat.
Obě řešení by se zřejmě dala zkombinovat následovně:
Odesílání v kroku 2) a 3) lze případně spojit do jedné operace.
Při přijímání přečteš hlavičku, přečteš serializovaná data a následně je deserializuješ. Přičemž vždy víš, kolik bajtů potřebuješ přečíst.
Netvrdím, že je to nějaké super řešení, ale nebudeš muset parsovat přijatá data.
Co se týče zamezení zasekávání při čekání na zprávy, můžeš jej řešit buď komunikací v samostatném vlákně, nebo asynchronními operacemi. U samostatného vlákna si ale sám musíš zajistit předávání zpráv do vlákna hlavního (pokud to má ty zprávy nakonec zpracovávat) včetně potřebné synchronizace.
U asynchronních operací nic takového obvykle dělat nemusíš, ale jejich sémantika může být poněkud "tajemnější". Nevím, jak je to v C#, tam třeba měli rozum a odstínili vás od pár ošklivostí... ale dělat asynchronní operace třeba přímo přes WIndows API není úplně triviální záležitost; je třeba pečlivě číst dokumentaci, aby to fungovalo ve všech případech.
Zobrazeno 5 zpráv z 5.