PDA

View Full Version : [C] client/server per scambio file


f.bandiera
06-04-2008, 18:21
Ciao a tutti ragazzi, ho un bisogno assoluto del vostro aiuto!
Devo implementare in C un client ed un server in modo che il client possa richiedere un file al server e quest'ultimo glielo invii.

Per iniziare mi sono studiato le socket... ok, ho scritto un client che si collega al server tramite indirizzo IP del localhost e il server gli rimanda a connessione avvenuta un messaggio di benvenuto "Hello Client", data, ora indirizzo IP del client, del server e le porte di "ascolto" della socket.

Bene, i due programmi comunicano correttamente usando le funzioni write/read...
ma dalle specifiche del progetto questo non è quanto richiesto.

Infatti mi viene detto che il client richiede il file al server tramite una chiamata del tipo:
GET /data/esempio.txt

e il server risponde con:
codice XXX parametro XXXXXXXXXXXXx
es.
codice: 201 parametro: PERMISSION DENIED
codice: 301 parametro: [dati del file]
ecc.

mi viene anche fornito il Protocollo seguente da rispettare come formato per ogni comando:
Message Length - 4 byte in ordinamento network
Message Code - 2 byte in ordinamento network
Message Parameter - potrebbe essere opzionale e le cui dimensioni dipendono dalle circostanze.

Quindi, mi sembra di capire che io NON devo implementare un semplice client/server ma qualcosa del tipo client FTP e server WEB.... giusto? o non ho capito un fiasco?

Poi ho letto che il protocollo http si basa per la trasmissione dei dati sul tcp/ip...
ok, MA come? quali sono le "chiamate" che devo usare?
se io decido di scrivere ogni comando nel formato dato (GET /../...) e poi con un banalissimo write lo passso alla socket e quando arriva al server lo faccio leggere e interpretare, e poi invio tramite una write del server la risposta al client...
ok, ci riesco, ma NON credo sia il modo giusto!
Non avrei bisogno di definire un protocollo e il "senso" di usare come istruzione GET (codice) (parametro) lo perdo, potrei usare "PRENDI" al posto di GET e non mi cambierebbe nulla......

come faccio in C ad usare le funzioni del protocollo http?
il "codice" del metodo GET dove piffero è definito?
come faccio ad usarlo?
E' qui che mi incarto e faccio confusione... c'è qualcosa che mi sfugge, lo sto cercando ma ancora niente...

AIUTOOOOOO!!!!!!!

cionci
07-04-2008, 00:40
se io decido di scrivere ogni comando nel formato dato (GET /../...) e poi con un banalissimo write lo passso alla socket e quando arriva al server lo faccio leggere e interpretare, e poi invio tramite una write del server la risposta al client...
Hai capito giusto. Quello che stai scrivendo è molto vicino alle prime versioni del protocollo HTTP.

Si scrive GET perché un giorno magari non ci sarà solo il tipo di richiesta GET, ma magari ci sarà anche POST o PUT (come in HTTP).
Quindi tu sul server devi controllare che il comando arrivi proprio con scritto GET ;)
Quello che tu hai chiamato protocollo è solo il formato della risposta del server.

f.bandiera
07-04-2008, 10:05
Ciao Cionci, intanto grazie per la risposta... è già un inizio!

Ma visto che appunto GET, POST, LIST ecc sono "comandi" già definiti in http con le loro strutture dati, i loro codice e le loro funzioni...
Come posso integrarli nel mio programma in C?

Http usa TCP/IP e la socket che creo è appunto costruita usando la "grammatica" del tcp/ip.... quindi dovrei poter sfruttare il protocollo http, no?
Per fare un qualcosa che sia simile (anche se un po' alla lontana) ad un telnet, dove devo scrivere i comandi che voglio usare appunto rispettando una certa grammatica:
nomecomando, versione HTTP, ecc ecc.

non sai dove trovare un esempio di webserver scritto in C o un client (browser) scritto sempre in C da studiare?

Comunque, come inizio, adesso mi ci metto per implementare i camandi GET e LIST come anche tu mi hai consigliato, se poi a qualcuno viene in mente qualche suggerimento... Datemelo!!!!!
Per favore!!!!

Ciao

f.bandiera
07-04-2008, 10:06
Sono super-ben-accetti anche link a tutorial, guide, dispense ecc.

Grazie

cionci
07-04-2008, 10:09
Il testo non mi sembra che ti dica assolutamente di implementare un server http. Ti dice di implementare qualcosa di simile.

Non ci sono strutture dati in http, o meglio la struttura dati è definita da testo separato dai caratteri line feed e carriage return.

Se vuoi l'esatto funzionamento di http guardati la RFC corrispondente.

Rigo007
07-04-2008, 10:33
Dai un occhio a un esempio TFTP scritto in C.
Altrimenti sul Stevens il titolo del libro è Unix Network Programming ne trovi un esempio già implementato che usa il protocollo UDP.

f.bandiera
07-04-2008, 10:38
Ciao rigo007, si, lo stevens è proprio il manuale di riferimento che sto usando, adesso guardo l'esempio che mi hai segnalato.
Grazie

Cionci, ho scaricato il documento rfc2616, ci do una occhiata!

Ciao, a presto

cionci
07-04-2008, 10:41
TFTP non è adatto, infatti si appoggia a UDP ;)

f.bandiera
08-04-2008, 17:07
Ciao ragazzi!
allora, ho implementato la trasmissione dei messaggi a seconda dei vari casi...
adesso devo superare l'ultimo scoglio!

In caso di errori (file non esistente, sintassi sbagliata ecc) sono a posto.
L'ultimo caso, quello in cui il file c'è e lo si può prendere, come faccio a passare un file di dimensione qualsiasi su una socket?

Per chiarire, quando usavo le sistem call per implementare comandi linux, nel caso del cp aprivo un file e poi lo leggevo facendo mettere le info in un buffer di dimensioni fissate e ripetevo l'operazione fin quando la read non mi dava 0 (cioè file terminato)....

Ora, come posso fare una cosa simile con una socket?
E ancora, visto che i file normali in linux sono un flusso di byte non formattato e le info su COME interpretare tale flusso sono nell'inode... se "passo" il file tramite la socket su due pc diversi, perdo le informazioni dell'inode oppure no?
Ed infine che cosa vuol dire "passare file binari" (l'ho trovato a proposito del passaggio di file con FTP)?

Potete chiarirmi?
Grazie 1000000

PS per Cionci, quando avrò finito il progetto, posso postare il codice o è meglio di no ?

Comunque sono disponibile in pvt all'indirizzo email

cionci
08-04-2008, 17:13
Certo che lo puoi postare ;)
Magari se è un esercizio di un qualche corso aspetta che ci sia stata la consegna.

Devi fare assolutamente la stessa identica cosa, leggi in un buffer parte del file e lo scrivi sul socket, continui fino a quando il file finisce.
Ovviamente devi scrivere anche gli header http, se stai implementando un server http.

f.bandiera
09-04-2008, 15:50
Ciao, ho ancora un problema...

Come posso impostare un "temporizzatore" su una socket?
In pratica, ho il mo server che gestisce più client e ogni client può chiedere di eseguire più comandi (è il client che chiude la socket quando processa il comando EXIT)....
Quello che devo ottenere, però, è che il server tenga traccia del tempo di connessione di ogni client e se uno o più di questi rimangono inattivi per 60 secondi, il SERVER deve chiudere la loro socket!!!

Potrei impostare un valore di alarm(60) e poi signal(SIGALRM, mio handler), dove alarm viene resettato a 60 sec ogni volta che viene ricevuto/eseguito un comando sulla socket....

Però quello che voglio sapere è se è possibile passare come argomento al mio signal handler non solo il codice del segnale SIGALRM ma ANCHE il mio socket descriptor in modo da poter chiudere la connessione all'interno del mio handler...

Oppure vorrei sapere se ci sono altri modi per definire un timeout allo scadere del quale chiudere automaticamente la socket


Ciao e grazie

cionci
09-04-2008, 16:31
Prima di tutto come gestisci i client ? Usi la select per controllare che siano arrivati dati sul socket ? In tal caso è banale, ti salvi il timestamp dell'ultima ricezione (uno per ogni client ovviamente), dopo ogni esecuzione della select controlli che la differenza fra il tempo attuale ed il timestamp non sia superiore al tempo limite, se è superiore chiudi la connessione.

f.bandiera
09-04-2008, 16:48
No, viste le richieste del profe seguo la prassi:

sockfd =sock
bind(sockfd)
listen(sockfd)
(SIGCHLD,SIG_IGN)

for ( ; ; )
new_sockfd = accept(sockfd)

if ( fork() == 0 )
{
//figlio
close(sockfd)
azioni del figlio
}
else
{
//padre
close (new_sockfd)
}
//ciclo nel for
}

f.bandiera
10-04-2008, 10:39
Ciao ancora...
l'idea che mi sembra più praticabile è la seguente:
//nel server
definisco un alarm(60)
che viene reimpostato ogni volta che ricevo qualcosa dalla socket
se arrivo a 0 -> si genera il segnale SIGALRM
voglio definire un mio gestore per il segnale suddetto....

1) con signal (SIGALRM, miohandler)
non riesco a fare nulla di buono, perchè intercetto il segnale, mi chiama la funzione miohandler, ma dentro non ho nessun lvalue per il socket descriptor che vogli chiudere

2) allora sto pensando a sigaction
sigaction mi "passa" anche una struct sigaction che è fatta da diversi campi che sto cercando di trovare e capire...
Potrei usare uno di questi per "passare" alla funzione di risposta al SIGALRM il valore del mio socket descriptor?

Qualche idea?
Ciao, francesco

cionci
10-04-2008, 10:46
Perché non usi la select su ogni singolo socket ? In questo modo fai la recv solo quando hai dati disponibili e non rimani mai bloccato. Sinceramente bisognerebbe vedere come si comporta il socket in caso di arrivo di un segnale gestito.

cionci
10-04-2008, 10:55
Fai qualche prova con la setsocketopt: http://linux.die.net/man/3/setsockopt
Come vedi SO_RCVTIMEO e SO_SNDTIMEO dovrebbero fare al caso tuo.

f.bandiera
10-04-2008, 11:07
Non uso select per due motivi uno buono e uno no:

quello no, perchè dovrei riadattare il codice che ho scritto io, ma anche quello che mi è stato dato come consegna, ciò presuppone studio, incubazione e realizzazione.
E anche se è bene studiare le varie possibilità offerte da C / Unix, in questo momento non ne ho il tempo (progetto da consegnare dopodomani)

quello buono...... non so perchè (mio lack di conoscenza) ma l'ho proposto al mio prof (dato che già mi avevi risposto ieri riguardo alla select) e LUI mi ha detto "lascia stare, non è così che ho pensato il progetto" .... .... .... .... ..... MAH!!!!!!!!!!!!!

Quindi mi ha fatto capire che (sempre LUI) vuole il gestore del segnale...
Quindi le mie conclusioni sono le seguenti:
1) metto alarm(60), signal(SIGALRM,miohandler)
e miohandler{exit(-1);}
così dovrebbe "uscire" dal processo figlio (che conteneva la socket) e quindi "chiudere la sock"
ma, sinceramente, come sistema MI FA SCHIFO!!!!

2) quello che avevo pensato è usare sigaction (me la sto guardando) che è un po' più potente...
in particolare sigaction mi passa nella sunzione il puntatore ad una struct sigaction che contiene a sua volta un puntatore ad una struct siginfo_t, tra i cui campi mi sembra esserci un:
int si_band /*band event*/
int si_fd /*file descriptor*/

e sto cercando di capire se sono campi che io posso "scrivere" dal mio main in modo da metterci dentro il file descriptor della mia socket..... tipo:
struct sigaction * siga;
siga->sa_sigaction->siginfo_t-> si_band/si_fd = sockfd;

ora, per vari motivi suppongo che la "grammatica" scritta sopra NON sia proprio esatta... però la mia idea è quella.
Così potrei avere DENTRO al miohandler l'lvalue per la socket e FINALMENTE potrei chiamare uno SHUTDOWN(sockfd, 2) che quanto meno mi chiude la socket e non fa brutalmente un exit del processo....


Che ne dici? Hai suggerimenti?
E' possibile fare quello che ho pensato o è una "perdita" di tempo?
Questo perchè come detto sopra devo consegnare domani ed è l'ultimo punto che mi manca
:muro: :muro: :muro: :muro: :muro: :muro:

Ciao

cionci
10-04-2008, 11:12
Purtroppo non sono molto esperto nella gestione dei segnali :boh:

f.bandiera
10-04-2008, 11:14
Non sapresti anche solodarmi un link ad un codice con qualche esempio (anche 1) dove sigaction viene usata?

Sto cercando ma non ne trovo....

cionci
10-04-2008, 11:26
A quanto sembra quella struttura siginfo_t viene riempita a seconda del tipo di segnale gestito.
http://www.opengroup.org/onlinepubs/009695399/functions/sigaction.html
http://www.cact.unile.it/facilities/XC6000/html-man/gapil/gapilsu153.html

manneshow
05-03-2009, 10:01
puoi postare il tuo esempio??

Devo fare una cosa simile e ho bisogno di un esempio per iniziare....