|
|
|
![]() |
|
Strumenti |
![]() |
#21 |
Senior Member
Iscritto dal: Nov 2002
Messaggi: 4329
|
lol è incredibile...sto leggendo anche il tutorial in eng...ho rinunciato a capire il whois.c circa a meta (mi sono perso)...alla fine, dopo le dovute premesse dell autore (che addirittura ha detto che chi non avesse mai visto c poteva consultare una guida per capire "di cosa si trattasse"), ha detto: "beh nulla di difficile finora"....è questo che intendo...mi infastidisce la mia persona, il mio cervello inutilmente goffo...caz se qualcuno ci arriva, vuol dire che si puo...la costante della mia vita è invece che capisco sempre le cose a posteriori e in maniera precaria...ma baffangulo a me stesso va...
__________________
|18k+|slk800|a7n8x|1Gb/ddr400|Gf4mx440|Pio108|WD 160Gb|Case|Uni|Album|AnimeClick|OneManga| |ClassicThrash!|BNR Metal|TrueMetal|Dime|Chuck| |
![]() |
![]() |
![]() |
#22 | |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Quote:
Queste cose penso le sai già, ma era per introdurre. Un socket è un modo per creare un collegamento tra due programmi: immaginalo come un tubo che trasferisce informazioni. il tubo ovviamente ha due estremità: una collegata al programma che chiede, l'altra collegata a chi ascolta. E' necessario specificare per le due estremità DOVE devono essere collegate. Ora, tu fai due programmi separati: server.c e client.c. server.c fa questo: crea una delle due estremità del tubo (il socket di ascolto). Il socket di ascolto, per essere raggiungibile dall'esterno, deve essere collegato all'indirizzo ip del pc su cui il server gira: in più giacchè possono esserci altri socket in ascolto su quell'ip, si deve specificare una porta di ingresso per quell'ip. Ogni ip puo' avere 2^16 porte: si sceglie una porta libera e non riservata, e spesso il numero della è internazionalmente riconosciuto da altri programmi per un servizio preciso. Ad esempio, la porta per le connessioni HTTP è 80. Per un tuo programma privato, usa una porta a caso dal numero alto, ad esempio 8100. Ricapitolando, il server crea un socket, lo lega (bind) ad un indirizzo ip ed ad una porta, e si mette in ascolto (listen). client.c fa questo: crea l'altra estremità del tubo (il socket di richiesta). ma non si mette in ascolto (facendo il bind su un ip-porta). Dopo la creazione del socket, semplicemente specifica un ip ed una porta a cui vuole parlare e si connette: se l'ip e la porta specificata esiste, il tubo viene creato. Una volta creato il tubo, il client scrive dei dati sul socket: questo dati vengono automaticamente recapitati al server, che viene avvisato quando dei dati arrivano: in più, all'arrivo dei dati, il socket del server indica DA CHI i dati sono arrivati (non può saperlo a priori, dal momento che tutti possono collegarsi). Per semplicità, il server (in automatico) sdoppia il socket di ascolto e lo collega stabilmente col socket di richiesta, così da gestire facilmente il dialogo. Il socket iniziale (che non a caso viene chiamato master socket) rimane cos' liber e pronto per altre richieste (che possono giungere mentre il server gestisce i dati). Arrivati i dati, il server li legge, li elabora, ed in base ai dati arrivati si comporta di conseguenza: scrive dei dati sul suo socket (quello sdoppiato per gestire la connessione). Appena scritti, il suo socket li manda al client, che li legge e li gestisce. Faccio un esempio banale: Il server crea il socket di ascolto, lo lega all ip-porta della macchina su cui viene eseguito e si mette in ascolto. Un client crea un socket e si collega al server. Una volta connesso, scrive sul socket la stringa "Ciao, come stai?". Il server riceve la stringa, sdoppia il suo master socket per gestire la connessione e legge su quest'ultimo socket i dati inviati. Legge "Ciao, come stai?" Il server è stato programmato per riconoscere una richiesta del genere. Quindi risponde, scrivendo sul suo socket sdoppiato la stringa "Tutto bene, grazie!". Questa stringa viene recapitata al client, che la legge e ad esempio la visualizza. Se il server non riconosce la stringa (perchè il programmatore del server implementa solo un set limitato di possibili richieste), mandaper esempio la stringa "Che volevi dire?": il client la riceve, vede che il server non ha capito e stampa ad esempio "Il server non ha capito...". Questo è il concetto: ovviamente le problematiche sono innumerevoli: ad esempio, se il server riceve una seconda richiesta da un altro client mentre sta elaborando un'altra richiesta, che si fa? O meglio, come fa?, dal momento che i linguaggi di programmazione sono procedurali. Il server in questo caso deve essere multiprocesso (o multithread in Windows), in cui ogni processo/thread gestisce autonomamente una connessione, ma la cosa si complica ed esula dalla semplice spiegazione di prima.
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson Ultima modifica di -fidel- : 24-02-2006 alle 10:54. |
|
![]() |
![]() |
![]() |
#23 |
Senior Member
Iscritto dal: Nov 2002
Messaggi: 4329
|
sei gentilissimo e ti ringrazio per il tempo che mi hai dedicato...il mio problema è pero sempre lo stesso; queste cose sono abbastanza facili da interiorizzare, insomma è il meccanismo client server...so cosa fa, ma non so come farglielo fare...una guida che spiega il cosa ma non il come non mi fara mai arrivare a un codice eseguibile, un esempio tangibile, almeno parlo per il mio cervello ristretto...server.c e client.c (in quel tutorial in italiano) che cosa fanno? so a cosa servono, ma se io volessi un programma che se io scrivo in console "come va?" lui mi risponda "bene grazie", quei due file come potrebbero servirmi? cioe basta mdificarli un po, ma è quel po che io non riesco a raggiungere intellegibilmente..alla fine sara una domanda banalissima e da newby, il fatto è che non avendolo mai visto me lo potro immaginare molto difficilmente (imho), mentre in qualsiasi tutorial ti spiegano "questi sono i metodi e funziona cosi" [...] "ora che sappiamo questo possiamo scrivere un p2p"....ovviamente è un esempio esagerato, ma è cosi che lo vedo...non sto parlando solo di questo caso, mi sembra che sia una costante della mia vita: qualsiasi cosa in cui mi infogno sono punto e daccapo, sembra che non ci arrivi alle cose, oppure su internet ci sono solo geni che gli dai il la eti scrivono mezza pagina di codice senza nemmeno pensare....sta cosa è frustrantissima perche son 3 mesi che dico "devo imparare a sockettare visto che l anno prossimo ho prog in rete e tanto mi tocchera", ma mi fermo sempre a uno scoglio qualsiasi....ora che ci ero vicino a infognarmi, capisco che manco con un esempio completo e funzionante riesco a raccapezzarmi...e non è perche mi manchi la logica di come funziona un client server (ripeto, sembra abb basilare e ovvio quello), ma perche non so come scrivere e dove scrivere quello che mi interessa...boh lassiamo perdere va che tanto sono una causa persa...
__________________
|18k+|slk800|a7n8x|1Gb/ddr400|Gf4mx440|Pio108|WD 160Gb|Case|Uni|Album|AnimeClick|OneManga| |ClassicThrash!|BNR Metal|TrueMetal|Dime|Chuck| |
![]() |
![]() |
![]() |
#24 | |
Senior Member
Iscritto dal: Jul 2005
Città: San Marino
Messaggi: 308
|
Quote:
![]() Uso CodeBlocks ![]()
__________________
![]() ![]() |
|
![]() |
![]() |
![]() |
#25 | |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Quote:
L'importante in una connessione client-server è stabilire la connessione. I tutorial normalmente spiegano proprio questo. Una volta stabilita la connessione, è importante sapere come inviare i dati: i tutorial spiegano anche questo: semplicemente si usano le funzioni read() e write() sui socket, proprio come fossero dei file aperti con fopen. Tutto il resto spetta a te programmatore. Il dialogo client-server viene implementato programmando il cosiddetto protocollo a livello applicativo. Ce ne sono di ben definiti (come l'HTTP). Semplicemente il server deve saper riconoscere un numero X di comandi, e reagire di conseguenza. Esempio: - Il server riconosce i comandi "CHE_ORE_SONO" e "CHE_GIORNO_E": se il comando non è riconosciuto invia un messaggio di errore. - il client manda al server la stringa "CHE_ORE_SONO". - il server legge la stringa: se è uguale ad uno dei comandi conosciuti, esegue la funzione associata. Il server riconosce i comandi ad esempio con un costrutto case, nulla di complicato. Nel nostro esempio, il server legge l'ora del sistema su cui è in esecuzione e la scrive sul socket per inviarla al client richiedente. - il client legge la risposta: se non è un messaggio di errore, prende la risposta e la elabora secondo i suoi comodi. Se è un messaggio di errore, si comporta di conseguenza. L'importante è imparare come scrivere su e leggere da un socket (facile) e soprattutto attendere che (nel caso della lettura) ci siano dei dati nel socket. Imparare a sincronizzare il tutto insomma. L'elaborazione dei comandi sta alla tua fantasia: o ti inventi un semplice protocollo di comunicazione (implementi insomma le parole conosciute dal client e dal server) oppure usi un protocollo esistente (sconsigliato per le prime prove...). Esistono dei protocolli internazionalmente conosciuti ai programmatori (come l'HTTP) proprio perchè sennò la comunicazione tra client e server sarebbe impossibile. Il client DEVE sapere quali comandi sono riconosciuti dal server, COME il server manda le risposte e COME il server si comporta in caso di errore. EDIT: appena ho tempo nel pomeriggio, prendo quei 2 esempi del tutorial italiano e li modifico in modo tale da implementare l'esempio che ho fatto rpima con CHE_ORE_SONO, così ti fai un'idea precisa. Appena posso riavviare il pc ed andare in Windows lo faccio ![]() EDIT 2: Anzi, se non mi sbaglio conservo ancora un esempio client server fatto come uno dei primi esercizi ai tempi dell'università, tutto commentato e per windows. Vado a controllare. EDIT 3: Uff sono già tutti a finestre, quindi c'è tutto il message loop di windows che non ti interessa in questo caso e ti incasinerebbe ancora di più. Te lo faccio da 0.
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson Ultima modifica di -fidel- : 24-02-2006 alle 14:07. |
|
![]() |
![]() |
![]() |
#26 | |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Quote:
Se non hai visual studio, vai sul sito Microsoft e scarica l'SDK API di Windows, è gratuita. Ma cmq dovrebbe già esserci su pc, ma non ne sono sicuro a dire il vero. Fai appunto un giro sul sito MS o con google.
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson |
|
![]() |
![]() |
![]() |
#27 | |
Senior Member
Iscritto dal: Jul 2005
Città: San Marino
Messaggi: 308
|
Quote:
![]() Ho cercato anche tra le cartelle del VC che tengo installato ma nulla Ho fatto pure la ricerca completa in tutto il C e ovviamente non mi ha trovato niente ![]() Sono costretto ad utilizzare CodeBlocks perchè VC non dispone di un'editor di .rc e poi nn mi ci trovo con quel compilatore ![]() Su google di quella libreria non trovo risultati in ita e nel resto delle lingue non trovo roba interessante ![]() Ho provato anche ad includere la libreria libws2_32.a appartenente alla raccolta delle librerie del Dev, ma niente ![]() Vi prego, ho urgente bisogno di fare un progetto con le socket ![]()
__________________
![]() ![]() |
|
![]() |
![]() |
![]() |
#28 | |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Quote:
![]() ws2_32.lib appena lo trovi, segnati la cartella in cui è contenuto e la dai in pasto al linker. Ah, c'è un metodo (che con il compilatore Microsoft funziona) per specificare gli stub .lib da usare direttamente all'interno del codice. Si usa la direttiva #pragma. Per farti un'idea, puoi guardare gli esempi di client e server che sto per postare ![]()
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson |
|
![]() |
![]() |
![]() |
#29 |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
@dnarod, ma anche a tutti quelli a cui interessa
![]() Posto qui un semplice ma didattico esempio di un programma client-server. Ho riscritto sia il client che il server da zero, quelli fatti nel tutorial erano un po' bizzarri su alcune scelte (tipo assegnare l'ip alla struct sockaddr in quel modo...). Ho scritto il codice completamente in plain C ed è tutto commentato (ho perso più tempo a commentare che a scrivere il codice ![]() Sono 2 files .zip, uno contiene il client, l'altro il server. Per semplicità, includo anche i file di progetto di visual studio (ho usato .NET): se avete VS .NET cliccate semplicemente sul file .sln per ogni progetto per aprirlo. Comunque, entrambi i programmi sono composti di un unico file .c ... Ah, ho inserito anche gli eseguibili: potete provarli subito quindi. Basta aprire due prompt dei comandi MS-DOS: in uno digitate simpleserver 8001 nell'altro digitate simpleclient 127.0.0.1 8001 in alternativa scrivete solo il nome dell'eseguibile per avere un breve help. Buon divertimento, e spero che vi sia utile ![]() EDIT: Per il client, ho dovuto mettere l'eseguibile in un file zip separato, altrimenti il forum non me li faceva allegare (per le dimensioni per lui eccessive...). EDIT 2: Dimenticavo, potete provare anche ad usare più client collegati ad un solo server. Basta aprire più prompt di MS-DOS (uno per ogni client) e lanciarli. Potete provare a lanciare i client su pc diversi anche (ovviamente)... Con più client sullo stesso server, potrete anche vedere i problemi che un server bloccante monoprocesso comporta.
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson Ultima modifica di -fidel- : 25-02-2006 alle 09:17. |
![]() |
![]() |
![]() |
#30 |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
|
![]() |
![]() |
![]() |
#31 | |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Quote:
Ho notato che su quel tutorial ci sono delle cose strane, come ad esempio: Codice:
sock_addr.sin_addr.S_un.S_un_b.s_b1=127; // indico l'indirizzo IP sock_addr.sin_addr.S_un.S_un_b.s_b2=0; sock_addr.sin_addr.S_un.S_un_b.s_b3=0; sock_addr.sin_addr.S_un.S_un_b.s_b4=1; Codice:
sock_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson |
|
![]() |
![]() |
![]() |
#32 | |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
Quote:
uso anch'io quella forma nel mio codice ![]() ne approfitto per chiederti: secondo te, quale di queste due assegnamenti sotto non funziona, e perchè ? miosock_addr.sin_port=htons(80); miosock_addr.sin_port=htons(atoi(argv[1])); |
|
![]() |
![]() |
![]() |
#33 |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Stamattina ho leggermente modificato il codice di SimpleClient.c per renderlo più snello. Inizializzo la struttura struct sockaddr_in del socket client una volta per tutte, invece di farlo prima di ogni connect.
Avevo fatto quella scelta per rendere più chiari i passi da compiere per connettersi ad un server, però ho reputato che fosse un esempio di programmazione non buona (c'era troppo overhead).
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson |
![]() |
![]() |
![]() |
#34 | |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Quote:
vanno bene entrambe, a patto che il primo parametro passato a riga di comando dal programma sia un numero. Se l'argomento della atoi() non è un numero o è un numero troppo grande, il valore di ritorno non è definito (al meglio restituisce 0). Non ti dà errore, ma la porta poi è sballata. Prova: assegna alla atoi una stringa, e poi leggi il valore assunto da miosock_addr.sin_port in questo modo: unsigned short int port = ntohs(miosock_addr.sin_port);
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson |
|
![]() |
![]() |
![]() |
#35 | |
Senior Member
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3736
|
Quote:
stranamente a me con la seconda forma .......argv[1]......non funziona all'attao della esecuzione. Il primo assegnamento mette in ascolto in modo corretto il server sulla porta 80, il secondo invece, su una porta indefinita. Non ho ancora svelato il mistero, boh ![]() |
|
![]() |
![]() |
![]() |
#36 | |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Quote:
![]() EDIT: il secondo metodo l'ho usato nel mio programma di esempio SimpleServer.c postato prima. Se vuoi dacci un'occhiata ![]()
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson |
|
![]() |
![]() |
![]() |
#37 |
Senior Member
Iscritto dal: Nov 2002
Messaggi: 4329
|
fidel sei un grande...grazie per i tips e per il lavorone che hai fatto! ho gia capito di piu su sti socket (anche se a dire la verita con java me la sono cavata al primo tentativo) ma non so come mai i prog che hai linkato non mi funzioano....forse sbaglio io?? li compilo e li eseguo ma non fanno nulla...sara che devo settare il compilatore in qualche modo (uso codeblocks che preferisco a devcpp) come dice nelle guide?
__________________
|18k+|slk800|a7n8x|1Gb/ddr400|Gf4mx440|Pio108|WD 160Gb|Case|Uni|Album|AnimeClick|OneManga| |ClassicThrash!|BNR Metal|TrueMetal|Dime|Chuck| |
![]() |
![]() |
![]() |
#38 | |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Quote:
![]() Se hai problemi di compilazione con Codeblocks, ho incluso gli eseguibili dei due programmi, così puoi provarli. Devi lanciarli a riga di comando (in due Prompt di MS-DOS separati come spiegato prima.) Se li lanci col doppio click esce subito perchè vuole dei parametri passati a riga di comando (e col doppio click non passi nulla), e WinXP di default chiude la finestra MS-DOS al termine dell'applicazione ![]() Cmq non ho capito bene, con Codeblocks compila ed esegue? Se è così, e vuoi lanciare il programma da codeblocks, devi dire al debugger di passare gli argomenti a riga di comando, altrimenti si ripete il discorso fatto prima sul doppio click. Vai nelle opzioni progetto di Codeblocks, cerca le opzioni del debugger e cerca un'opzione che parla di "command line argument": lì ci scrivi gli argomenti da passare. Sennò è come se lanci il programma senza parametri (dal prompt MS-DOS è come se scrivessi solo il nome del programma: prova con il prompt (lo trovi nel menu' Start->Accessori') e vedi cosa succede a lanciare i due programmi senza argomenti ![]()
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson |
|
![]() |
![]() |
![]() |
#39 |
Senior Member
Iscritto dal: Jan 2006
Messaggi: 2722
|
Scrivo un piccolo promemoria delle operazioni effettuate dal client e dal server sui socket per abilitare la connessione, penso possa tornare utile (ed è questo lo schema che ho seguito nei due programmi allegati prima):
il server: 1) crea il master socket (quello che ascolta per le connessioni in arrivo) 2) definisce l'indirizzo e la porta su cui si metterà in ascolto (nel programma allegato, per l'indirizzo del server, uso l'indirizzo speciale INADDR_ANY: in questo modo il programma legge automaticamente l'indirizzo ip della macchina su cui il programma stesso è in esecuzione, senza così doverlo specificare manualmente come parametro) 3) lega (bind) l'indirizzo-porta specificati al master socket 4) si mette in ascolto 5) all'arrivo di una richiesta di connessione, la accetta. Quando la accetta, la funzione 'accept()' restituisce in caso di succeso un nuovo socket, che serve a gestire la connessione con il client: in questo modo il master socket rimane libero per l'ascolto di nuove connessioni. 6) Inizia il dialogo con il client connesso, effettuato sul nuovo socket restituito dalla 'accept()' 7) Alla fine chiude il socket creato dalla 'accept()'. Il master socket ovviamente resta in ascolto... All'arrivo di una nuova connessione si riparte dal punto 5). Il client: 1) Crea il socket per collegarsi al server 2) definisce l'indirizzo e la porta del server a cui vuole collegarsi (che sono quelli su cui il server è in ascolto...) 3) si connette (tramite la funzione 'connect()') 4) se la 'connect()' ha successo, la connessione è già stabilita con il server. Il dialogo è effettuato utilizzando lo stesso socket usato per la connessione (a differenza del server che usa un socket dedicato, assegnato dalla 'accept()'). 5) Alla fine chiudo il socket. Per effettuare una nuova connessione, deve si riparte dal punto 1). Se il server a cui ci si vuole connettere è lo stesso, si può saltare il punto 2), altrimenti (giustamente) bisogna ridefinire l'indirizzo e la porta del nuovo server a cui ci si vuole connettere.
__________________
- Spesso gli errori sono solo i passi intermedi che portano al fallimento totale. - A volte penso che la prova piu' sicura che esiste da qualche parte una forma di vita intelligente e' il fatto che non ha mai tentato di mettersi in contatto con noi. -- Bill Watterson Ultima modifica di -fidel- : 25-02-2006 alle 12:59. |
![]() |
![]() |
![]() |
#40 |
Senior Member
Iscritto dal: Jul 2005
Città: San Marino
Messaggi: 308
|
Ma possibile che se includo le librerie mi vengono comunque gli errori?
![]() Non mi riconosce il tipo sockaddr_in ed ho provato a linkare in tutti i modi quelle maledette librerie ![]() Con il pragma o andando nelle opzioni del CodeBlocks, ma nulla ![]() Aiutooo ![]()
__________________
![]() ![]() |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 01:53.