Newsgroup: it.comp.programmare.win32
Titolo: weila`! :-)

 (2:332/529)

 AfxBeginThread (AcceptConnection, LPVOID(this));
E invece dovresti fare:
SOCKET s = sockSrvr.Detach();
AfxBeginThread (AcceptConnection, (LPVOID)s);
Poi, nell'altro thread:
DWORD AltroThread( LPVOID pParam)
{
   CSocket nuovoSocket;
   socket.Attach( (SOCKET)pParam);
ecc...
Comunque di solito al thread separato si passa gia` il client socket
(quello che ti restituisce Accept)... cosi` hai un "server thread" che
accetta le connessioni e crea tanti "client thread". Questo e` uno
schema volutamente semplificato, ma funziona. :)
... Circular Definition: see Definition, Circular.
---
Bye! Lorenzo Lutti
http://www.geocities.com/SiliconValley/Peaks/6258/

Hello Lorenzo!
09 Mar 00 18:44, Lorenzo Lutti wrote to All:
 LL> Ciao! Scusa se nella WIN_PRG sono sparito, ma ho problemi col point
 LL> (sto passando a un point con binkd (*)). :-)
Figurati...
 LL> (*) A proposito, tu non hai un meganodo gigante dotato anche di
 LL> accesso con binkd? :)
Si, solo che non avendo una dedicata, si affaccia ad inet solo pochi minuti al giorno, nel corso dei quali avviene lo scambio di posta binkd nonche` soup, per i newsgroup e le e-mail della BBS. Se ti interessa, sono a disposizione.
 LL> Stai all'occhio perche` i socket sincroni di MFC sono rognosetti.
 LL> Quando li crei in un thread e li usi in un altro, e` necessario fare
 LL> un detach dell'HSOCKET, passarlo all'altro thread, e fare un attach in
 LL> un nuovo socket.
Uhmm... credo di capire.
 LL> SOCKET s = sockSrvr.Detach();
 LL> AfxBeginThread (AcceptConnection, (LPVOID)s);
 LL> Poi, nell'altro thread:
 LL> DWORD AltroThread( LPVOID pParam)
 LL> {
 LL>    CSocket nuovoSocket;
 LL>    socket.Attach( (SOCKET)pParam);
Ecco. Pero` in questo modo non ho piu` accesso alle altre variabili della classe principale della Dialog, vero?
Nel frattempo le cose si sono notevolmente evolute (o involute... dato che le ho portate avanti io).
Come esperimento ho scritto un programma in grado di trasmettere il testo inserito in una editbox ad un'altra istanza dello stesso programma, che gira su una macchina in rete IP con la prima, e viceversa. Per semplicita` il programma compilato e` uno solo, ed ha sulla dialog i bottoni necessari a far partire il server e/o il client. Ovviamente posso anche fare le prove lanciando due volte il programma sulla stessa macchina, purche` il suo IP sia quello cui .Connect fa riferimento.
Orbene, dopo aver constatato i problemi sull'uso di un socket in thread diversi, la strada che ho preso e` stata quella di gestire completamente la comunicazione nel thread separato. C'e` un tasto che avvia il server lanciandone il thread. Questo thread definisce i socket e li usa; non esce fino a quando non viene premuto il tasto di Stop, che comunica col thread mediante una variabile (temo che ci siano meccanismi piu` sofisticati, ma io volevo concentrarmi sul lavoro riguardante la rete). Ho fatto tutto in modo attento e non ci sono conflitti, il thread parte e si ferma benissimo. Se la connessione cade, il thread non esce ma chiude e riapre la porta, in attesa di un nuovo client.
Idem vale per il client. Premendo il bottone Connect, viene lanciato il thread che definisce ed utilizza un socket per connettersi al server.
Entrambi i thread comunicano con le rispettive editbox e con una mega-editbox readonly nella quale i messaggi provenienti dall'altro capo della rete vengono scritti attra verso il solito dlg->variabile.
Per poter gestire contemporaneamente ricezione e trasmissione, ho dovuto passare ad CAsyncSocket invece di CSocket. In questo modo, per esempio, ho un loop che attende il pacchetto di header senza blocking e nel frattempo controlla se c'e` una stringa da trasmettere proveniente dalla editbox locale.
Funziona tutto. Ci sono pero` alcune cose non bellissime. Ad esempio il Client, che prima eseguiva il .connect con blocking ed in caso di fallimento restituiva un CONNREFUSED (qualcosa del genere) ad indicare che il server non era aperto, ora passa direttamente dal messaggio WOULDBLOCK (qualcosa del genere, nel qual caso rimango nel loop) a ALREADYCONN (qualcosa del genere) perche` si e` collegato senza pero` restituire OK alla funzione .connect.
Ho allora visto che dovrei utilizzare le funzioni callback: OnConnect.
Ho fatto una prova in un programma ultra-semplice che avevo sviluppato all'inizio, con OnClose, per vedere se riuscivo ad accorgermi della caduta di un collegamento ad opera del client.
Per farlo ho dovuto derivare una mia classe (era la cosa giusta?):
miaAsync : CAsyncSocket
alla quale ho aggiunto la funzione membro miaAsync::OnClose, la quale emette un semplice BEEP.
Funziona: se il client chiude, avverto il beep nell'altoparlante.
Non riesco pero` ad implementarla nel programma grosso, perche` tutto si svolge nei famosi thread separati e la funzione non viene semplicemente chiamata.
Prima di leggere la tua risposta stavo pensando di rifare tutto utilizzando le callback, vale a dire avere il bottone che apre il server che lancia .listen, poi ci pensa OnConnect ad andare avanti, ecc. ecc...
 LL> Comunque di solito al thread separato si passa gia` il client socket
 LL> (quello che ti restituisce Accept)... cosi` hai un "server thread" che
 LL> accetta le connessioni e crea tanti "client thread". Questo e` uno
 LL> schema volutamente semplificato, ma funziona. :)
...pero` questo mi piacerebbe un casino... credo pero` che il multicollegamento lo lasciero` ad una successiva prova.
Per il momento, come credi che dovrei adare avanti? Non sarebbe male fare come dici qui sopra, pero` mi resta il problema di accedere alle variabili della classe principale avendo usato il parametro passato al thread come puntatore all'oggetto SOCKET...
Non e` possibile continuare a passare (this) ed eseguire Detach e Attach mediante dlg->? In questo modo, potrei
1) Col bottone far partire il .listen
2) con la callback OnConnect lanciare il thread separato che gestisce tutto
...ma quando viene chiamata la callback, mi spieghi come faccio a stabilire a quale oggetto di classe miaAsync si riferisce il messaggio? :-)
Scusa se ti ho scritto tutto quello che ho fatto in questi due giorni, ma dovevo pur compensare l'off-topic iniziale su binkd... <g>
A parte gli scherzi, se mi dai qualche dritta, la prossima settimana potro` continuare gli esperimenti in modo piu` ortodosso...


 Detach e Attach mediante dlg->? In questo modo, potrei
Certamente! Come ho detto, ci sono varie possibilita`. Tutto sommato,
dato che "avviene" tutto all'interno di una classe, puoi anche pensare
di far comunicare i thread fra loro attraverso le variabili
protette/private della classe...
[dopo un attimo] Sono riuscito a riesumare uno spezzone di codice "di
esempio" che ho spedito tempo fa. L'ho riadattato per fare in modo di
passare anche this. Non ho usato una variabile condivisa perche` e`
concettualmente un po' "sporco". Pensa ad esempio se (anche se in
realta` non succedera` mai!) arrivasse una nuova richiesta di
connessione prima che la vecchia struttura SOCKET venga 'riattachata':
verrebbe modificata senza preavviso, con esiti infelici...
Nota anche che il "ciclo" che accetta le connessioni e` sviluppato su un
thread a parte (ServerThread), a cui va passato 'this' quando si crea.
typedef struct
{
    CMyWnd* wnd;
    SOCKET sock;
    // altre variabili che vuoi passare...
} THREAD_DATA;
UINT CMyWnd::ServerThread( LPVOID pParam)
{
    CMyWnd *wnd = (CMyWnd*)pParam;
    CSocket ServerSocket;
    CSocket ClientSocket;
    if( !ServerSocket.Create( porta) ||
        !ServerSocket.Listen())
    {
        // Gestione errori
    }
    for(;;)
    {
        if( ServerSocket.Accept( ClientSocket))
        {
            THREAD_DATA *td = new THREAD_DATA;
            td->wnd = wnd;
            td->sock = ClientSocket.Detach();
            if( !AfxBeginThread( ClientThread, (LPVOID)td))
            {
                // Gestione errori
                delete td;
            }
        }
    }
}
UINT CMyWnd::ClientThread( LPVOID pParam)
{
    THREAD_DATA* td = (THREAD_DATA*)pParam;
    CSocket sock;
    if( !sock.Attach( td->sock))
    {
        // Gestione errori
    }
    // Codice di gestione del socket...
    delete td;
    return 0;
}
... (You can have your cake) XOR (You can eat your cake)


Hello Lorenzo!
12 Mar 00 20:59, Lorenzo Lutti wrote to All:
 >> Ecco. Pero` in questo modo non ho piu` accesso alle altre
 >> variabili della classe principale della Dialog, vero?
 LL> No, infatti. Se vuoi passare piu` parametri puoi sempre usare una
 LL> struttura (che contenga sia la variabile SOCKET che il puntatore
 LL> all'istanza della classe, ad esempio), o qualcosa del genere... hai
 LL> varie possibilita`.
Quindi in sostanza potrei anche continuare a passare tutti i dati della classe, usando this, avendo l'accortezza di includere una variabile HSOCKET fra i membri della CDialog? (Lo so che e` piu` brutto, e` solo per capire se ho capito).
 >> CSocket. In questo modo, per esempio, ho un loop che
 >> attende il pacchetto di header senza blocking e nel
 >> frattempo controlla se c'e` una stringa da trasmettere
 LL> Inizialmente anche io ho scritto diversi programmini che facevano
 LL> cosi`... e` vero, funziona, pero` non definirei esattamente "ordinato"
 LL> il codice che ne esce fuori. ;-)
Gia`. Nel frattempo ho scritto una versione funzionante che utilizza le callback. Anche questa e` monotask, ma funziona molto bene. Ho pero` fatto una cosa che potrebbe essere strana, ovvero ho derivato DUE classi dalla CAsyncSocket: una, completa di buffer e variabili varie, che uso per la connessione vera e propria sia dal lato server che client; l'altra serve solo per l'Accept (e quindi non ha tutte le variabili dell'altra) e possiede solo un membro: OnAccept().
 LL> Non ho mai approfondito piu` di tanto i socket asincroni... so che
 LL> permettono di fare cose piu` "sofisticate", ma per ora non ne ho avuto
 LL> bisogno.
E` stato il mio esperimento n.5 (net5.exe) :-)
 LL> [dopo un attimo] Sono riuscito a riesumare uno spezzone di codice "di
 LL> esempio" che ho spedito tempo fa. L'ho riadattato per fare in modo di
Con questo potrei lanciare tanti thread quante sono le connessioni in arrivo, eh?
Provero` appena avro` tempo a farne la mia net6.exe. <g>


 connessioni in arrivo, eh?
Ancora esatto. :-)
