|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Senior Member
Iscritto dal: Jan 2001
Città: California
Messaggi: 7174
|
socket TCP su C
Ho questo problema:
lavoro su socket TCP su C, spedisco un sacco di messaggi da un host all'altro, pero' il secondo host non riceve niente (sta bloccato sulla read) finche' l'host che spedisce non chiude la connessione o gli faccio io un kill -9...perche'? Se sono stato troppo vago fatemelo sapere... ciao e grazie Cimmo |
![]() |
![]() |
![]() |
#2 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Diminuisci il buffer della read...
|
![]() |
![]() |
![]() |
#3 |
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Dovrebbe funzionare ugualmente, in quanto la read dovrebbe ritornare anche se è disponibile una quantità di dati inferiore a quella richiesta (blocca solo se non ci sono dati).
Puoi mandare il codice incriminato? (sia del client che del server)
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
![]() |
![]() |
![]() |
#4 |
Senior Member
Iscritto dal: Jan 2001
Città: California
Messaggi: 7174
|
Non posso mandarvi tutto il codice perche' e' una pappardella che non ci cavereste i piedi, pero' vi mando quello che riceve e dopo un po' di debug ho scoperto qualcosa.
Io mi sono fatto una funzione per ricevere i messaggi (quella che posto dopo nel messaggio) e lui cosa fa: praticamente va' avanti a leggere pero' non becca mai il delimitatore '\0' e quindi non esce mai dal while e cosi' neanche dalla funzione. Diminuendo il buffer non fa altro che fare piu' giri di while per leggere tutto, pero' quando ha finito si inchioda lo stesso in attesa del e non esce. Se pero' il processo che spedisce termina, allora il processo che contiene questa funzione si sblocca...mi sapreste dire il perche'? grazie e 1000 ciao Cimmo int receiveData(int socketfd, char *msg) { int nread, n; /* lettura */ nread=0; printf ("\nread()\n"); fflush(stdout); while (1) { if ((n=read(socketfd, &(msg[nread]), MAXSIZE)) <=0) { if (errno!=EINTR) { char msgerror[1024]; sprintf(msgerror,"read() failed [err %d] ",errno); perror(msgerror); fflush(stderr); return(1); } } else { nread+=n; if ((msg[nread-1]=='\0') || (nread>=MAXSIZE)) break; } } fflush(stdout); return(0); }; |
![]() |
![]() |
![]() |
#5 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Ma tu sei sicuro di spedirlo lo '\0' ?
Se la stringa che spedisci è lunga 10 caratteri...dovrai spedirne 11 con la send... |
![]() |
![]() |
![]() |
#6 |
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Codice:
if (errno!=EINTR) { char msgerror[1024]; sprintf(msgerror,"read() failed [err %d] ",errno); perror(msgerror); fflush(stderr); return(1); } } else { nread+=n; Codice:
if ((msg[nread-1]=='\0') || (nread>=MAXSIZE)) break; Nessuno può assicurarti che più pacchetti non siano stati riassemblati prima della read, dopo essere stati ad es. divisi a metà durante la trasmissione. Questo vuol dire che con una singola read ne puoi ricevere uno e mezzo, poi altre due metà ecc. Devi controllare tutti i byte ricevuti in una read, alla ricerca di eventuali '\0' intermedi. Il tcp è stream, ma la dinamica del flusso non la puoi controllare.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
![]() |
![]() |
![]() |
#7 | ||||
Senior Member
Iscritto dal: Jan 2001
Città: California
Messaggi: 7174
|
Quote:
Quote:
Addirittura succede cosi': faccio partire il server che si mette in attesa, faccio partire il client che si connette e comincia a spedire al server il quale riceve, ma si inchioda come ho gia' spiegato, poi il client a suo volta lo faccio bloccare e tutto rimane bloccato. Se a manoni uccido (con kill -9) il client, il server si sblocca dalla read e mi ritorna magicamente tutto il messaggione con tutto quello che ho spedito. Cosa devo fare? |
||||
![]() |
![]() |
![]() |
#8 | ||||
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Quote:
Quote:
Poi potresti mettere dei messaggi di debug dopo la read per vedere quello che succede. Nota che il risultato della read è <0 se c'è stato un errore e ==0 se il client si è disconnesso (e in questo caso errno rimane indefinito)
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
||||
![]() |
![]() |
![]() |
#9 | |
Senior Member
Iscritto dal: Jan 2001
Città: California
Messaggi: 7174
|
Quote:
Comunque il debug l'ho fatto (con DDD) e mi si inchioda sulla read non boccheggia il '\0'... |
|
![]() |
![]() |
![]() |
#10 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Se è una stringa lo '\0' c'è sempre in fondo...e per definizione una stringa in C è una sequenza di caratteri a aprtire da un certo indirizzo con un '\0' che indica la fine della stringa...
Quindi se quello che mandi è una stringa allora c'è lo '\0' in fondo e per mandarlo devi dare la dimensione strlen(str) + 1 alla send... |
![]() |
![]() |
![]() |
#11 |
Senior Member
Iscritto dal: Jan 2001
Città: California
Messaggi: 7174
|
Ok nella send ho messo strlen(s)+1, io faccio 5 write:
1) scrivo 1/ 2) scrivo 6/ 3) scrivo 247/ 4) scrivo 1/ 5) scrivo 3/ e il risultato e' che invece di arrivarmi 1/6/247/1/3/ mi arriva cosi': 1/\0006/\000247/\0001/\0003/\000 perche'? grazie della pazienza! |
![]() |
![]() |
![]() |
#12 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Ci puoi far vedere il modo in cui costruisci i messaggi che invii ?
|
![]() |
![]() |
![]() |
#13 |
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Congruente con quello che ti ho detto. Leggendo MAXSIZE byte, dici al kernel di "svuotare" la coda tcp fino ad un massimo di MAXSIZE byte. Ovviamente i pacchetti che sono arrivati fin'ora vengono "impacchettati" e letti tutti insieme dalla read().
Soluzioni possibili: - Leggi 1 byte per volta (bleah!) - Dividi la lettura in 2 strati: uno (quello attuale) che legge i dati e li mette in un buffer fregandosene di trovare gli '\0'; un altro che legge dal buffer, cerca la prima occorrenza di '\0' ed estrae la stringa dal buffer. - Prima di spedire una stringa, spedisci un int indicante la sua lunghezza. Così non hai neanche necessità di inviare lo '\0' finale.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
![]() |
![]() |
![]() |
#14 | ||||||
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
Comunque ha ragione ilsensine...fai una lettura a due livelli... |
||||||
![]() |
![]() |
![]() |
#15 | ||||||
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Quote:
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
||||||
![]() |
![]() |
![]() |
#16 |
Senior Member
Iscritto dal: Jan 2001
Città: California
Messaggi: 7174
|
Cosi' costruisco le stringhe...
strcpy(data,""); sprintf(tmp,"%d/",TotHosts); strcpy(data,tmp); sendData(socketfd, data); printf("%s\n",data); alla fine infatti a me del delimitatore \0 non me ne frega niente, cosa dovrei fare cambiare l'ultimo if della receiveData e invece di ricercare il '\0' ricerco il '/'? Tutti quei \0 io non li metto, non so come ci finiscono! |
![]() |
![]() |
![]() |
#17 |
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Forse fai qualcosa di sbagliato nella sendData.
nb tmp è inutile, basta fare sprintf(data,"%d/",TotHosts);
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
![]() |
![]() |
![]() |
#18 |
Senior Member
Iscritto dal: Jan 2001
Città: California
Messaggi: 7174
|
Eccovi anche la sendData, ora c'e' len=strlen(msg) senza il +1, ma come vi ho detto ho gia' provato entrambi i modi ed e' andata come sapete...
int sendData(int socketfd, char msg[MAXSIZE]) { int nwrite, len, n; /* scrittura */ //len=strlen(msg)+1; len=strlen(msg); nwrite=0; printf ("\nwrite()\n"); fflush(stdout); while ((len-nwrite)>0) { if ((n=write(socketfd, &(msg[nwrite]), (len-nwrite))) <=0) { if (errno!=EINTR) { char msgerror[1024]; sprintf(msgerror,"write() failed [err %d] ",errno); perror(msgerror); fflush(stderr); return(1); } } else nwrite+=n; } return(0); }; |
![]() |
![]() |
![]() |
#19 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Per leggerti le varie stringhe terminate con '/' puoi ad esempio farti una cosa del genere :
Codice:
int readMsg(char *buf, char *msg, int nread) { static int start = 0; int cur = start; int n = 0; len = strlen(msg); while(n < (MSGMAX + 1 - len) && cur < nread) { if(buf[i] == '/') break; else { ++n; ++cur; } } if(n == (MSGMAX + 1 - len)) { /*lunghezza del messaggio eccessiva, te la puoi gestire come ti pare ad esempio riempiendo il msg corrente oppure riportando l'errore ed ignorando il buffer fino al prox '/'*/ ... return 2; } if(cur == nread) { /*il msg è a metà fra due letture, riempio la parte corrente*/ buf[nread] = '\0'; strcpy(msg+len, buf+start); start = 0; /*riparto dall'inizio del buffer dopo una nuova lettura*/ return 1; } /*se arrivo qui significa che ho trovato lo '/'*/ buf[cur] = '\0'; strcpy(msg+len, buf+start) start = cur + 1; return 0; } .... char buf[READMAX+1]; /*buffer di ricezione*/ char msg[MSGMAX+1]; /*contiene il messaggio ricevuto*/ while(1) { nread = leggiDaSocket(buf); if(nread > 0) while(!readMsg(buf, msg, nread)) { /*qui ti gestisci il messaggio letto...ad esempio lo puoi visualizzare*/ printf("%s ", msg); strcpy(msg, '\0'); } } .... |
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 10:11.