[ Yeremiya @ 10.09.2009. 14:07 ] @
Nedavno sam se suočio sa problemima vezanim za download fajla sa servera (serverska aplikacjia, thread-ovan TcpServer, pisan za .NET 3.5 SP1) na klijent (klijentska aplikacija, konektuje se na server putem socket-a). Klijent radi na Motorola Symbol uređaju, Windows Mobile platforma, sasvim korektno, korišćen je .NET Compact Framework. Server radi na Windows XP mašini na koji je nakačen Access Point za bežično povezivanje sa klijentskim mašinama. Klijent i server koristim za "kratku" komunikaciju koristeći sopstveni kvazi-protokol koji se zasniva na slanju UTF8 stringova sa separatorima. Npr: klijent pošalje DATA1,DATA2,DATA3, server primi, parsira i vrati odgovor tipa ODGOVOR1,ODGOVOR2,ODGOVOR3. Ovakav način komunikacije sam testirao i testirao i sve radi kako treba. Međutim, nedavno sam dobio potrebu da sa servera pošaljem binarni fajl na klijent, na zahtev klijenta. Osmislio sam komunikaciju ovako: 1) klijent pošalje specifičan zahtev za download fajla 2) server primi zahtev, isparsira ga i pošalje odgovor u formatu IME,VELIČINA (šalje kao string), a zatim šalje fajl 3) klijent prima odgovor i parsira ga, pravi FileStream f u folderu sa imenom iz odgovora servera, pravi byte[] buffer = new byte[VELIČINA], i zatim prima fajl Fajl je binarni, šaljem array bajtova "u komadu" jer se nisam snašao sa implementacijom algoritma koji bi podatke slao u delovima (npr po 1024 bajta odjednom). U C# kodu bi to izgledalo ovako: Klijent: Code: // slanje zahteva serveru string msg = "DL,FILE1"; byte[] tosend = new UTF8Encoding().GetBytes(msg); socket.Send(tosend, tosend.Length, SocketFlags.None); // prijem odgovora byte[] received = new Byte[1024]; int bRead = socket.Receive(received); string serverMsg = Encoding.UTF8.GetString(received, 0, bRead); // parsiranje odgovora, odgovor stiže u formatu IME,VELIČINA string[] split = serverMsg.Split(",".ToCharArray()); string ime = split[0]; long length = Convert.ToInt64(split[1]); // priprema za download fajla string curFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName); string fname = curFolder + "\\" + ime; byte[] fajl = new byte[length]; // buffer za prijem fajla // prijem fajla long primljeno = socket.Receive(fajl, SocketFlags.None); // upis fajla na disk FileStream fs = new FileStream(fname, FileMode.Create); fs.Write(fajl, 0, fajl.Length); fs.Close(); Server: Code: TcpClient client; // ovde ovo navodim samo radi razjašnjavanja koda, client je već konektovan u ovom koraku!!!! NetworkStream ns = client.GetStream(); // server je već primio i parsirao zahtev za download ispravno, pa krećem od dela gde server šalje odgovor na klijentov zahtev FileStream fs = new FileStream(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName) + "\\file.bin", FileMode.Open); FileInfo fi = new FileInfo(Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName) + "\\file.bin"); long total = fi.Length; // dužina fajla string msg = fi.Name + "," + total.ToString(); // poruka za slanje, "IME,DUŽINA" byte[] tosend = new UTF8Encoding().GetBytes(msg); // odgovor koji sadrži dužinu fajla i ime ns.Write(tosend, 0, tosend.Length); byte[] fajl = new byte[total]; // buffer za čitanje fajla sa diska i slanje klijentu fs.Read(fajl, 0, fajl.Length); fs.Close(); // slanje fajla klijentu ns.Write(fajl, 0, fajl.Length); Ono što se dešava nakon što pokušam da fajl prenesem je da prenos u stvari uspe. Međutim, u testovima fajl ni jednom nije stigao do klijenta a da nije bio corrupted. Napominjem da sam pokušavao i sa dodavanjem BinaryReader-a na serverskoj strani za čitanje fajla i BinaryWriter-a na klijentskoj za upis fajla, ali i pored toga sam dobijao identične rezultate. Da li neko zna gde grešim? Možda je način slanja celog fajla odjednom loš, s'obzirom na to da je veličina fajla oko 5MB? Ako je tako, kako da implementiram slanje "deo-po-deo"? Unapred zahvalan na odgovorima, Yeremiya |