[C#] Server TCP

lunedì 28 maggio 2012 - 14.36
Tag Elenco Tags  C#  |  .NET 4.0  |  Windows 7  |  Windows Vista  |  Windows XP  |  Visual Studio 2010  |  Visual Studio Express

gabry90 Profilo | Newbie

Salve a tutti. Scrivo qui perchè ho un grosso problema da risolvere.
Sono alle prese (purtroppo xD) con le socket in C# per la creazione di un server di un gioco multi-player.
In pratica ho un server che resta in ascolto, in una determinata porta, di connessioni in entrata. e fin qui va tutto bene.
Il problema sussiste quando voglio che una volta che il mio client si è scollegato faccia determinate azioni, In pratica vorrei gestire una sorta di "sessione del client". E' possibile farlo?
Il fatto è che non so proprio come stilare il codice per quello che voglio fare io. Cioè, il mio client si connette e invia al server l'username del client, poi il server accetta la connessione e salva in memoria la sua connessione, al momento della disconnessione del client il server fa qualcosa (es. mandare un messaggio a video).

StefanoRicci Profilo | Junior Member

>Salve a tutti. Scrivo qui perchè ho un grosso problema da risolvere.
>Sono alle prese (purtroppo xD) con le socket in C# per la creazione
>di un server di un gioco multi-player.
>In pratica ho un server che resta in ascolto, in una determinata
>porta, di connessioni in entrata. e fin qui va tutto bene.
>Il problema sussiste quando voglio che una volta che il mio client
>si è scollegato faccia determinate azioni, In pratica vorrei
>gestire una sorta di "sessione del client". E' possibile farlo?

di preciso intendi memorizzare della roba nella ram del server?
se così, e vuoi scrivere un pò di codice, potresti agganciare il client, inserire la sua richiesta in un thread, ed usare delle liste che allocano le tue variabili di sessione... aggiungendo un controllo di timeout nel caso il client salti all'improvviso...

>Il fatto è che non so proprio come stilare il codice per quello
>che voglio fare io. Cioè, il mio client si connette e invia al
>server l'username del client, poi il server accetta la connessione
>e salva in memoria la sua connessione, al momento della disconnessione
>del client il server fa qualcosa (es. mandare un messaggio a
>video).

per questo basta che sul client fai un bottone di logoff, che non fa altro che mandare il comando di chiusura tramite tuo protocollo al server, e rimane in attesa di una qualche risposta, e sulla base di questa risposta si comporta di conseguenza.... inserendo sempre il solito controllo di timeout

--------------------------------------

IDE: Visual Studio 2008 Professional Edition
IDE: Visual Studio 2010 Professional Edition

gabry90 Profilo | Newbie

mmmm...ti ringrazio per la risposta ma ho capito ben poco xD.
allora...il fatto è che voglio fare un vero è proprio server per le sessioni (come quelle in php), nel senso che voglio che tutte le connessione fino a quel momento accettate vengano messe in memoria (forse intendevo dire istanziate xD) e poi riprese per essere controllate se ce ancora o meno connessione o si sono disconnesse). la teoria lo capita...ma in pratica come faccio?

StefanoRicci Profilo | Junior Member

>mmmm...ti ringrazio per la risposta ma ho capito ben poco xD.
>allora...il fatto è che voglio fare un vero è proprio server
>per le sessioni (come quelle in php), nel senso che voglio che
>tutte le connessione fino a quel momento accettate vengano messe
>in memoria (forse intendevo dire istanziate xD) e poi riprese
>per essere controllate se ce ancora o meno connessione o si sono
>disconnesse). la teoria lo capita...ma in pratica come faccio?

le sessioni in php rimangono legate alla comunicazione con il browser, per come le ho sempre usate io (con la chiamata session_start()), quindi dati che spariscono, a meno che non salvi sul client un cookie con i dati che vuoi mantenere (o tutti i dati nel client, oppure un id che ti permette di recuperare lo stato dal database)... ma quest'ultima modalità non l'ho mai usata per i mie lavori...

quindi per emulare questa cosa devi mettere in piedi un server che ascolta le richieste del client, quando il client si collega sposta il controllo e l'intera gestione ad un thread.... nel thread puoi mettere tutti i controlli che vuoi...

questo thread, che gira sul server, avrà delle variabili di sessione che gestisci nei modi che preferisci (liste, array, ecc)...
per ricontrollarle, magari è meglio che fai una lista di thread contenente tutti i riferimenti ad i vari thread (ci stà una classe che permette di automatizzarti, senza scrivere niente, questo tipo di gestione, ThreadPool)

se vuoi mantenere lo stato per periodo indeterminato, la prima variabile che negozi dovrebbe essere un ID univoco che identifica il client in particolare co la relativa sessione (un semplice datetime ti dovrebbe bastare), che sia server sia cliet devono memorizzare...
sul server avrà lo scopo di storare i dati su memoria di massa.
sul client invece servirà per dire cosa ricaricare.

per gestire dal client la memoria del server (una sorta comportamento simila all'array $_SESSION), potresti usare un tuo protocollo di comunicazione (un pò come l'http per capirci, ma naturalmente versione molto basic)

per quel che riguarda i controlli per sapere se esiste ancora comunicazione, potresti inserire nel tuo protocollo chiamate periodiche per dire al server che il client è ancora online

--------------------------------------

IDE: Visual Studio 2008 Professional Edition
IDE: Visual Studio 2010 Professional Edition

gabry90 Profilo | Newbie

ecco..ehm..ti stai avvicinando xD
allora..io la pensavo cosi, poi correggimi se sbaglio..allora a grandi linee io scriverei cosi (come pseudocodice)

list<client> lista = new list<client>();

tcplistener server = new tcplistener(ipaddress.any, porta);

exit = false;
while (!exit)
{
list.add(client cl = new client(server));
client.connect();
for (int i = 0; i < lista.length; i++)
{
if (lista[i].EndConnection()) { fai qualcosa }
}
}
server.close()


public class client

tcplistsener server 0 null;

public client(tcplistener server)
{
this.server = server;
}

public void Connect() { non so cosa scrivere xD }

public void EndConnection() { idem qua }

ect. etc.

penso che cosi forse potresti aiutarmi meglio :)

StefanoRicci Profilo | Junior Member

>ecco..ehm..ti stai avvicinando xD
>allora..io la pensavo cosi, poi correggimi se sbaglio..allora
>a grandi linee io scriverei cosi (come pseudocodice)
>
>list<client> lista = new list<client>();
>
>tcplistener server = new tcplistener(ipaddress.any, porta);
>
>exit = false;
>while (!exit)
>{
> list.add(client cl = new client(server));
> client.connect();
> for (int i = 0; i < lista.length; i++)
> {
> if (lista[i].EndConnection()) { fai qualcosa }
> }
>}
>server.close()

invece che fare il loop in questa modalità inserisci la gestione a thread... con l'evento nuova connessione, lo lanci, portando il controllo della sessione nelle sue mani...

ora, se ti serve avere un controllo sincronizzato delle sessioni, usi un ThreadPool, altrimenti se è un controllo a livello di singola connessione, ma ognuna indipendente, usi un semplice Thread che lanci senza tenerne traccia... in entrambi i casi ti porti dietro una sottoscrizione ad un stream di eventi che poi usare per mantenere server padre in contatto con server figli...

per un esempio basta che cerchi server multi connessione e trovi tutto il codice che vuoi..

ps: è il server che controlla se esiste ancora connessione, e lo fa spedendo le informazione sulla socket attiva.... tu stai facendo una chiamata alla classe che rappresenta il client, il che non ha senso... essendo due strutture completamente scisse... il server non conosce cosa implementa a livello di codice il client... ma parlano tramite un protocollo di comunicazione, che di solito si gestisce a livello di stringhe di testo contenenti comandi e parametri

>
>
>public class client
>
>tcplistsener server 0 null;
>
>public client(tcplistener server)
>{
>this.server = server;
>}
>
>public void Connect() { non so cosa scrivere xD }
>
>public void EndConnection() { idem qua }
>
>ect. etc.
>

nella Connect() basta che metti l'apertura della socket...
la EndConnection(), per come la usi sopra è inutile, a meno che non implementi in questo metodo la spedizione di logoff tramite protocollo... ma è il client solo che usa il codice


>penso che cosi forse potresti aiutarmi meglio :)
>

--------------------------------------

IDE: Visual Studio 2008 Professional Edition
IDE: Visual Studio 2010 Professional Edition

gabry90 Profilo | Newbie

si scusa end connect è una funzione bool che restituisce true o false :)

cmq non riesco a capire il meccanismo, cioè, nella endconnect è quindi possibile verificare se su quella istanza di client è presente o meno ancora la connessione? perchè se si può fare praticamente ho risolto il problema :)

StefanoRicci Profilo | Junior Member

exit = false; while (!exit) { list.add(client cl = new client(server)); client.connect(); for (int i = 0; i < lista.length; i++) { if (lista[i].EndConnection()) { fai qualcosa } } } server.close()

tutta queste parte per come è scritta non ha senso, in quanto hai mischiato molto il codice dei due differenti ruoli... devi rivederlo per forza staccando completamente le due classi ed il modo con cui li fai dialogare, in particolare se vuoi realmente apprendere come creare uno stack client-server su socket (tieni presente che client e server di solito li trovi scritti in differenti linguaggi)

come pseudo codice avresti su SERVER solo questo:

while (true)
{
WaitClientConnection(); // resta fermo quì il codice fino a che non si connette un client
PassControlToThread();
}

sul Thread che il server crea per gestire il client (se non fai così puoi gestire solo UNA connessione alla volta per porta), avresti il controllo della singola connessione, con verifica periodica che il client sia online... per esempio gli spedisci una sorta di ping ogni 30 sec, e lui ti risponde...

tendenzialmente potresti non dover avere nessun codice riferito al client, in quanto non necessario.... ma se lu vuoi scrivere è naturale che lo devi fare secondo questo criterio...

prova a guardarti questi link per chiarirti un pò la questione:

* http://www.switchonthecode.com/tutorials/csharp-tutorial-simple-threaded-tcp-server
* http://www.dreamincode.net/forums/topic/33396-basic-clientserver-chat-application-in-c%23/


--------------------------------------

IDE: Visual Studio 2008 Professional Edition
IDE: Visual Studio 2010 Professional Edition

gabry90 Profilo | Newbie

allora. intanto chiedo scusa perchè quello chje ho scritto era appunto un peudocodice a grandi linee. ovvimaente il ciclo while è dentro una void in un thread separato e si hai ragion eè da dividere, io lo scritto insieme ma perchè sono scemo XD, in realtà intendevo che il controllo sulla disconnessione va fatto su un'altro thread, il problema nasce quando voglio verificare che su quel determinato client si disconnette la connenssione, io ho per esempio 10 client connessi al server, il 3 client si disconnette e il server riconosce che è il 3 client ad essere disconnesso. insomma, alla fine vorrei fare una cosa semplice, io mi collego, il server accetta,mimpostaa 1 sul database, mi scollego, imposto a 0 sul database. con php non ho la precisione, quindi con i socket se io mi disconnetto lo scopro all'istante, non so poi se esistono altri metodi masuchisti per farlo xD ma non credo :).

cmq quella guida lo gia vista e rivista ma ci credi se ti dico che non ci capisco nulla?

StefanoRicci Profilo | Junior Member

>allora. intanto chiedo scusa perchè quello chje ho scritto era
>appunto un peudocodice a grandi linee. ovvimaente il ciclo while
>è dentro una void in un thread separato e si hai ragion eè da
>dividere, io lo scritto insieme ma perchè sono scemo XD, in realtà
>intendevo che il controllo sulla disconnessione va fatto su un'altro
>thread, il problema nasce quando voglio verificare che su quel
>determinato client si disconnette la connenssione, io ho per
>esempio 10 clint sconnessi al server, il 3 client. insomma, alla
>fine vorrei fare una cosa semplice, io mi collego, il server
>accetta,mimpostaa 1 sul database, mi scollego, imposto a 0 sul
>database. con php non ho la precisione, quindi con i socket se
>io mi disconnetto lo scopro all'istante, non so poi se esistono
>altri metodi masuchisti per farlo xD ma non credo :).

quindi vuoi che sul database ci sia semplicemente un numero che dice che se online oppure off? oppure una variabile che ti riesca a dire quanti client ci sono connessi al momento?

in entrambi i casi per sapere se un client è o meno operativo e online devi crearti un tuo protocollo di scambio messaggi che ti permetta di saperlo...
in PHP è molto semplice il meccanismo... se tu attivi la sessione, tutti i dati spariscono quando chiudi il browser (cambia l'identificativo univoco) oppure dopo un certo lasso temporale (impostato da chi configura il web server)... (do per assunto che non usi cookies)

nel tuo caso per fare la stessa cosa non devi fare altro che:
* sostituire alla chiusura del browser, un messaggio che il client lancia al server, in cui gli dice, "guarda che mi disconnetto"
* sostituire alla gestione temporale del web server, un tuo controllo di timeout sulla connessione.... e decidere la politica relativa... puoi fare uno scambio periodico di messaggi che verifica se il client è ON e, nel caso ti ritorna un errore sul socket, vuol dire che è caduto... associare alla creazione dell'ID univoco un scadenza che dice per esempio, dall'ultima volta che ti ho visto ON, se passa più di 3 gg cancella tutto...

>
>cmq quella guida lo gia vista e rivista ma ci credi se ti dico
>che non ci capisco nulla?

questo è un problema, in quanto sono esempi molto basic sul meccanismo teorico del rapporto client server
--------------------------------------

IDE: Visual Studio 2008 Professional Edition
IDE: Visual Studio 2010 Professional Edition

gabry90 Profilo | Newbie

ma è proprio per questo che voglio fare un server è non un php, a me non mi interessa sapere se il client è on da 1 secondo, 3minuti o 3 giorni, no voglio ne un controllo temporaneo ne un controllo diretto la client, voglio che sia il server a gestire una sola cosa, se cade la connessione allora imposta il valore a 0, indipendentemente se lo sloggamento avviene in maniera sponatanea perchè ho cliccato io logout oppure perchè è saltata la connessione al client o perchè si è bruciato il computer o per qualsiasi altro motivo che a me non mi importa e che giustamente posso o non posso sapere io dal lato amministrativo, la cosa importante è che io sappia se in quel preciso istante ce o non l aconnessione. se ce metti 1, s eon ce metti 0, troppo facile cosi come lo detto o troppo difficile cosi come la penso?

StefanoRicci Profilo | Junior Member

se vuoi fare un check sullo stato della connessione solo lato server incorrerai nel problema che in c#.net non viene dato nessun metodo nativo, ma devi girarci attorno...

come strada puoi tentare quella espressa qui http://bytes.com/topic/c-sharp/answers/538900-determine-if-socket-connected
--------------------------------------

IDE: Visual Studio 2008 Professional Edition
IDE: Visual Studio 2010 Professional Edition

gabry90 Profilo | Newbie

anche se la guida che mi hai postato è praticamente illeggibile :) cercherò di tradurla..cmq per fare l'avvocato del diavolo avrei usato php solo se bon avesse un piccolo difetto. ovvero: come faccio a fare una determinata cosa una volta che termino la sessione perché mi cade la connessione o perché mio fratello ha preso a calci il pc ed ora non va piu? il php lo sa? chiudo il browser, e poi? non fa piu niente...quindi per questo sono passato a la server, se cade qualcosa il server continua a girare (previa distruzione del server sull''hosting, ma questa è un'altra storia xD).

mentre cerco di tradurre questa favolosa guida ben formattata xD potresti illumnarmi le idee su come controllare la conenssione, magari con un po di codice piu comprensibile? cmq hai azzeccato, è quello che cercavo :)

StefanoRicci Profilo | Junior Member

>anche se la guida che mi hai postato è praticamente illeggibile
>:) cercherò di tradurla..cmq per fare l'avvocato del diavolo
>avrei usato php solo se bon avesse un piccolo difetto. ovvero:
>come faccio a fare una determinata cosa una volta che termino
>la sessione perché mi cade la connessione o perché mio fratello
>ha preso a calci il pc ed ora non va piu? il php lo sa? chiudo
>il browser, e poi? non fa piu niente...quindi per questo sono
>passato a la server, se cade qualcosa il server continua a girare
>(previa distruzione del server sull''hosting, ma questa è un'altra
>storia xD).

il PHP è un linguaggio di scripting lato server... se vuoi fare cose strane puoi fare girare in parallelo alla navigazione/gestione del browser uno script lanciandolo con CURL, che gestisci tramite file di testo o campo nel database... non puoi controllarlo in altri modi, in quanto irraggiungibile dall'esterno...

>
>mentre cerco di tradurre questa favolosa guida ben formattata
>xD potresti illumnarmi le idee su come controllare la conenssione,
>magari con un po di codice piu comprensibile? cmq hai azzeccato,
>è quello che cercavo :)

questa è una guida cercata al volo praticamente, a parte il css che andrebbe rivisto, il succo è che basta che cerchi online e ne trovi molteplici di questi esempi... basta che metti: socket connection status c#... essendo un problema molto sentito allo stato attuale ci sono svariate soluzioni per aggirare il problema... di cui alcune te le ho citate...

--------------------------------------

IDE: Visual Studio 2008 Professional Edition
IDE: Visual Studio 2010 Professional Edition

gabry90 Profilo | Newbie

ok.grz cmq per le risposte. spero di riuscire a tirar fuori qualcosa che funziona :)

SE A QUALCUNO PUO INTERESSARE ECCO LA SOLUZIONE A QUESTO PROBLEMA:

accetto la connessione in un ciclo while fintanto che pending non riceve una connessione (alternativa di acceptsocket che è bloccante) in fatti accept socket lo richiamo una volta eseguito il pending.

poi alla fine per controllare la disconnessione ecco il codice:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

ho messo il cilco try per differenziare la disconnessione manuale o involontaria (dovuti a vario fattori, quale disconnessione improvvisa, mancanza di linea, chiusura del pc immediata, insomma...tutto cioè che non è voluto). Quando ce disconnessione manuale nel ciclo non genera alcuna eccezione, quando invece è involontaria viene generata l'eccezione socketexception, e quidni basta intercettarla e farlo uscire in ogni caso e etvoila, il gicoo è fatto. TESTATO E FUNZIONANTE.
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2017
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5