Newsgroup: it.comp.programmare.win32
Titolo: Problema con Winsock e invio dati

Ciao a tutti vengo subito al problema..Sto creando un applicazione
server in C, questa applicazione deve leggere un file (di qualsiasi
dimensione) e inviarlo pezzo per pezzo a un client che provvederà a
ricostruirlo e crearlo...Per questo motivo ho creato un pacchetto che
viene inviato dal server e serve oltre che per riconoscimento anche per
varie informazioni, tenendo sempre conto che a ogni dato che invio dal
server è sempre presente questa intestazione.
Il problema sta nel fatto che se cerco di inviare dati consistenti
(4000 byte) con un ciclo, i dati in uscita (dopo un pò) non contengono
l'intestazione e quindi il client non riconosce il server e chiude la
comunicazione. La cosa ideale sarebbe stabilire un modo per far inviare
dal server quel pezzo di dato di 4kb che contenga sicuramente
l'intestazione e che finisca, in modo che quello successivo sia
corretto ma da quanto ho capito con tcp/ip è un pò dura...Avete
qualche idea? Questo è il codice:
BYTE bytVetFile[32000];
while (dwLetti!=0)
  {
     // Legge il fil
     pbFile = bytVetFile;
    ReadFile(hFile,pbFile,32000,&dwLetti,NULL);
    if (dwLetti>0)
      {
       pbPacket = bytVetPac;
        //pbPacket = calloc(4000+3+4,sizeof(int));
       pbPacket[0] = 0xAA;
       pbPacket[1] = 0x11;
       pbPacket[2] = 0xFF;
       pbPacket[3] = 0x5;
       // inserimento della dimensione della parte spedita nel
pacchetto
        for (k=0; k<=2; k++)
       {
         pbPacket[4+k] = Dividi_Dimensione(hwndapp,dwLetti,k,1);
      }
      // inserimento della dimensione del file
        for (k=0; k<=4; k++)
       {
         pbPacket[7+k] = Dividi_Dimensione(hwndapp,dimensione,k,2);
       }
    for (k=0; (DWORD)k<dwLetti; k++)
    {
       pbPacket[12+k]=pbFile[k];
    }
  // Invia al client
  send(sClient,pbPacket,dwLetti+12,0);
  }
Dove i due cicli centrali non sono importanti e servono per inserire la
dimensione del file all'interno del pacchetto

 qualche idea?
Ci sono alcune cose del codice che usi per inviari i dati che non sono 
chiare:
- con la ReadFile leggi 32000 byte ma non vedo che li suddividi in pacchetti 
da 4K bensi' aggiungi in testa le due dimensioni (quella dei byte letti e 
quella totale del file) e poi invii il pacchetto per intero
- questa Dividi_Dimensione che suppongo utilizzi per estrerre i byte di un 
intero (inteso come 2 byte) e di un long (inteso come 4 byte) e' in un ai un 
loop che va da 0 a 2 compreso (e quindi sono 3 i byte che carichi) ed un 
altro che va da 0 a 4 (e quindi sono 5 i byte). Non sapendo pero' come 
funziona questa Dividi_Dimensione potrebbe essere anche giusto cosi'
Sarebbe anche interessante sapere come cerchi di leggerli questi dati.
Magari il problema e' nella lettura perche' visto che i dati vengono 
ulteriormente spezzati in pacchetti di lunghezza imprevedibile nella 
trasmissione con il socket magari sbagli qualcosa a ricostruire i tuoi 
pacchetti originali da 32000 o 4K che siano.
Comunque non vedo la necessita' di indicare per ogni pacchetto la 
dimensione.
Tuo hai la misura totale del file che puoi inviare dopo l'header e quando 
leggi un header valido ti aspetti la dimensione e poi vai avanti a leggere 
finche' non hai finito tutto.
Piuttosto se proprio vuoi mettere un controllo che la lettura sia corretta 
puoi mettere un bel checksum al fondo.
-- 
Guglielmo
I programmatori passano il tempo a combinare cose ovvie in modi non ovvi
(Robert Dewar)

In effetti c'è un errore:
ReadFile(hFile,pbFile,4000,&dwLetti,NULL);
Che ho già corretto ma il problema persiste.
Le funzioni Dividi_Dimensione funzionano e non è lì il problema...Il
problema sta appunto nella lunghezza imprevedibile dei dati inviati dal
socket che devo in qualke modo riuscire a gestire..

Il comportamento che ho notato è circa il seguente, tenendo conto di
un pacchetto ad esempio di 5 elementi inviati con un ciclo di 2
elementi alla volta:
Array: A,B,C,D,E (contenuto dell'array da inviare)
Teoricamente dovrebbe inviare:
Intestazione A B
Intestazione C D
Intestazione E
Invece invia ad esempio
Intestazione A
B
Intestazione C D
Intestazione E
Dato che l'elemento B è senza intestazione chiaramente non viene
riconosciuto. Il discorso è che nella realtà A, B, C, D, E sono
blocchi di dati inviati all'interno del mio ciclo e dopo un certo
numero di ricorsioni comunque

drav...@virgilio.it
 ha scritto:

Penso ti convenga strutturare un po' meglio.
Ti posto qui una base, vedi se ti puo' servire
------------
struct header
{
// come ti piace di piu'
//  DWORD Magic;
  BYTE Magic[4];
  // inizio | intermedio | fine | ...
  DWORD Code;
  DWORD Len;
  DWORD Chksum;
};
BYTE buffer[4000];
header Head;
DWORD chksum(LPBYTE buff, DWORD len)
{
// quello che ti piace di piu'
#if 1
  DWORD sum = 0;
  for(DWORD i = 0; i < len; ++i)
    sum += buff[i];
  return sum;
#else
  DWORD xor = 0xf1c0;
  for(DWORD i = 0; i < len; ++i) {
    xor ^= (DWORD)buff[i] << (i & 3);
    if(!xor)
      xor = 0xcafe;
    }
  return xor;
#endif
}
1) leggi dal file su un buffer
2) prepari l'header
3) invii l'header e poi il buffer
4) se non è terminato il file riparti da uno
------------
Ciao

 numero di ricorsioni comunque
Come supponevo il problema e' nella lettura! Non puoi aspettarti di ricevere 
i pacchetti esattamente come li hai spediti.
Devi implementare una lettura sequenziale di quello che ricevi e 
immagazzinarlo in un buffer, dopo fai l'interpretazione.

pacchetti con i socket dall'altra parte arrivino suddivisi in modo diverso!
Si il problema non è nell'invio ma nel tcp stesso che fa i pacchetti
come vuole lui. Questo a me viene scomodo perchè io ho bisogno di
inviare un pacchetto, riconoscerlo (dal client) e fare qualcosa in base
al tipo di pacchetto...Chiaramente se in un ciclo vengono inviati tanti
pacchetti e il tcp li manda come vuole, se arriva un pacchetto di tcp
contenente tutti i miei pacchetti allora li prendo e non c'è problema
(ho già risolto questo) ma se mancano anche ad esempio un pezzo di mio
pacchetto che verrà inviato al successivo, allora questo non avrà
l'intestazione e il mio client non riuscirà ad elaborare i dati
ricevuti...

Inoltre volevo chiedere (dato che sto pensando di separare il tutto in
un thread a parte) se la mia funzione ha 3 parametri in ingresso:
(SOCKET, char *, HWND), come posso fare a inviare tutti e tre i
parametri alla funzione di avvio del thread?

 wrote in message
news:1147787014.2...@y43g2000cwc.googlegroups.com...

Gli passi un puntatore a struttura nell'argomento LPVOID e gliela precompili
;)
Sko

 ricevuti...
...perche' devi gestirti un buffer di lettura.
1) Attendi di ricevere uno stream di dati dal server e li accodi ad un 
buffer.
2) Appena il buffer di dati ricevuto e' lungo almeno 7 byte del tuo header 
controlli se sono validi. Se non sono validi hai ricevuto un header 
sbagliato e quindi puoi gia' scegliere di interrompere la lettura.
3) Continui a leggere byte dal server e li accodi al buffer finche' non hai 
raggiunto la lunghezza che ti aspettavi e che ti e' stata passata con 
l'header.
4) Quando hai ricevuto tutti i byte del pacchetto (potresti averne ricevuti 
anche di piu', non importa), interpeti il pacchetto che hai ricevuto e lo 
rimuovi dal tuo buffer di lettura e ritorni al punto2 per vedere se quello 
che ti e' rimasto nel buffer e' gia' l'header del pacchetto successivo 
oppure se devi ancora ricevere dei dati.
Questa e' quasi la prassi quando hai a che fare con qualunque dispositivo di 
input, non c'e' niente di strano nel doversi implementare un buffer di 
lettura.
-- 
Guglielmo

 ha scritto nel messaggio 
news:1147787014.2...@y43g2000cwc.googlegroups.com... 

lettura.
Si ma ad esempio il mio client (sviluppato in Visual Basic), riceve in
un colpo tutto il dato che il server ha mandato, controlla quanti
pacchetti (miei) sono presenti all'interno e li suddivide per bene
mettendoli in un array (di stringhe in questo caso), dopodichè
controllerà tutti i pacchetti uno ad uno ed eseguirà le varie
istruzioni. Non capisco proprio come fare a "scaricare" un carattere
alla volta cioè il dato ricevuto è quello e rimane quello poi dopo lo
posso leggere un carattere alla volta e finito il pacchetto arriverà
il seguente...

 il seguente...
L'ho spiegato in un altro post. Quale parte non ti e' chiara? 

>L'ho spiegato in un altro post. Quale parte non ti e' chiara?
Ti faccio un esempio in VB che è comunque riconducibile anche al C:
tcpClient.GetData strPacket, vbString
...
...
...
Ricevo in strPacket quello che il server ha mandato (che sia un pezzo o
tutto), successivamente dovrei eseguire delle operazioni su quello che
ho ricevuto ma da quanto ho capito devo aspettare di avere tutto il
dato quindi se ad esempio in strPacket c'è un mio pacchetto e mezzo
come faccio a dire: Ok dammi il pacchetto successivo? Cioè quando
realmente posso compiere le operazioni sui dati ricevuti?

 realmente posso compiere le operazioni sui dati ricevuti?
Lo puoi fare quando il buffer in cui accodi man mano i dati che riceve dal 
server contiene un pacchetto completo.
In pratica ogni volta che ricevi dei dati in strPacket li aggiungi ad un 
buffer (strBuffer = strBuffer + strPacket) e poi chiami una funzione che 
controlla se in strBuffer c'e' un pacchetto completo (header + dati).
Se c'è un pacchetto completo lo puoi finalmente interpretare e poi 
rimuoverlo dal buffer e controllare se in strBuffer ci sono altri pacchetti, 
altrimenti aspetti di ricevere altri dati e la storia si ripete.
Per rimuovere il tuo pacchetto dal buffer dovrai fare qualcosa tipo 
strBuffer = mid (strBuffer, HEADER_SIZE + PACKET_SIZE) ....