Avatar
buri
Člen
Avatar
buri:

Ahojte,

Mám takýto problém a potrebujem ho nejak riešiť alebo navrhnúť optimálne riešenie.

Keďže som si chcel v praxi uplatniť moje schopnoti OOP atp., rozhodol som sa spraviť si mini hru: Hadík Multiplayer. :D

To zahŕňa aj binárnu sieťovú komunikáciu. To všetko už mám navrhnuté a funkčné. Jediné, čo ma brzdí a neviem sa s tým pohnúť ani pomocou strýka Google, sú asychnorické volania Socket.BeginRe­ceiveFrom().

Totiž, keď zavolám AsyncCallback() a spracujem v ňom dáta, potrebujem aby som zavolal funkciu s nejakým parametrom ale už na hlavnom vlákne.

Totiž nechcem volať metódy medzi sebou na rôznych vláknach. Chcem aby sa dáta prijali a aby sa ďalej nespracovávali asychrónne.

Dám príklad z môjho existujúceho riešenia:

1. Tu inicializujem Socket server

socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.EnableBroadcast = true;
socket.Bind(new IPEndPoint(IPAddress.Any, this.port));

IPEndPoint client = new IPEndPoint(IPAddress.Any, 0);
EndPoint epSender = (EndPoint) client;
socket.BeginReceiveFrom(this.buffer, 0, this.buffer.Length, SocketFlags.None, ref epSender, new AsyncCallback(serverOnData), epSender);

2. Tu je spomínaný AsyncCallback

private void serverOnData(IAsyncResult ar)
{
        NetworkInstruction ni = new NetworkInstruction(this.buffer);
        IPEndPoint client = new IPEndPoint(IPAddress.Any, 0);
        EndPoint epSender = (EndPoint)client;
        this.socket.EndReceiveFrom(ar, ref epSender);

        // tu potrebujem dáta poslať späť do main threadu na ďalšie vykonávanie

        // A pokračujeme v príjmaní
        socket.BeginReceiveFrom(this.buffer, 0, this.buffer.Length, SocketFlags.None, ref epSender, new AsyncCallback(serverOnData), epSender);
}

3. Toto je metóda ktorú by som chcel zavolať z asychónnej metódy ale uź pod main threadom

private void onData(EndPoint ep, NetworkInstruction ni)
{
        if (!ni.signed)
                return;

        // ...
}

Dôvodom je, že medzi cestou mám aj Formy, a aj iné veci ktoré potreujem vykonávať pod pôvodným threadom.
A keď zavolám nejakú zmenu na form-e (teda presnejšie na Control-e) tak mi to hlási cross-platform.

Viem že sa to dá cez Invoke, ale pokiaľ viem tak toto má len Control a ja by som radšej
to celkovo oddelil nech nemusím na to pamätať ale len si to prenesiem do hlavného threadu a pokračujem.

Čiže v AsyncCallback by som chcel čislo len dáta prijať a maximálne spracovať do Packet Class-u :)

Ako sa to dá riešiť?

Vďaka :)

Odpovědět 3.4.2014 10:29
Prvý dojem klame!
Avatar
buri
Člen
Avatar
buri:

Tak už som to konečne spravil.
Pre tých ktorý by chceli vedieť ako som to poriešil.

V novom .NET Frameworku 4.5 je nová featura a to: Synchronizati­onContext.
(Čo mi nie moc vyhovuje ale budiź, na tento test to postačí)

Pri BeginReceiveFrom ako state(object) pošlem Synchronizati­onContext.Current
(aj v AsyncCallbacku toto prepíšeme)

socket.BeginReceiveFrom(this.buffer, 0, this.buffer.Length, SocketFlags.None, ref epSender, new AsyncCallback(serverOnData), SynchronizationContext.Current);

Potom upravím onData metódu:

private void onData(object arguments)
{
    object[] objs = arguments as object[];

    if (objs.Length != 2)
        return;

    NetworkInstruction ni = objs[1] as NetworkInstruction;
    EndPoint ep = objs[0] as EndPoint;

    // ...
}

A v AsyncCallbacku to zavoláme takto:

// ...

// tu potrebujem dáta poslať späť do main threadu na ďalšie vykonávanie
SynchronizationContext sc = ar.AsyncState as SynchronizationContext;
sc.Post(onData, new object[] { epSender, ni });

// ...
Nahoru Odpovědět 9.4.2014 8:56
Prvý dojem klame!
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 2 zpráv z 2.