Изпращане на файл през неблокиращ сокет, GuardianeLinks - Форум за програмиране на Delphi

За да се присъедините към „Accepted Coder“ трябва:Напишете 10 полезни съобщения или теми и вземете 10 харесвания.За тези, които не искат да губят време, могат да дарят средства в подкрепа на услугата и да се присъединят към VIP ранговете за един месец, повече информация в ЛС.

Заместник администратор

изпращане

В интернет има много статии, описващи технологията за изпращане и получаване на файл, включително и на този сайт. Но всички тези статии описват получаването само на една част от данните или съобщението, дошло до клиента, и последващата обработка на този блок в процедурата ClientSocket1Read / ServerSocket1ClientRead. Но трябваше да изпратя файл, в идеалния случай с произволен размер, и да придружа всичко това с анимация на лентата за напредък. Следователно методите sendtext и sendstream не бяха подходящи, защото те не дават възможност да се визуализира процеса на изпращане на файла част по част.

//изпращане на файл чрез сокет процедура TForm1.SendFileSocket(fName: низ); var nSend : Цяло число; sBuf : показалец; започнете опитайте // отваряне на файл за четене и след това изпращане на fs := TFileStream.Create(edt1.Text, fmOpenRead); // курсор към началната позиция, от която да изпратите файла fs.Position := 0;

повторение // заделяне на памет за прочетени данни GetMem(sBuf, bSize + 1); // четене на част от данни (bSize) от файл nSend := fs.Read(sBuf^, bSize); // ако нещо е прочетено, тогава го изпраща на клиента ако nSend > 0 след това започнете ServerSocket1.Socket.Connections[0].SendBuf(sBuf^, nSend); // коригиране на стойностите на лентата за напредък ​​ Прогрес (fs.Position, fs.Size); // забавяне, в противен случай ще има загуба на пакети Sleep(SleepTime); край; // освобождаване на част от паметта FreeMem(sBuf); Application.ProcessMessages; до nSend 0 след това започнете ServerSocket1.Socket.Connections[0].SendBuf(sBuf^, nSend);

Ако поне нещо е прочетено в sBuf буфера, тогава можете да изпратите това „поне нещо“ на клиента. В моя случай тестването беше извършено с 1 клиент, който се установи в ServerSocket1.Socket.Connections[0], но можете да организирате например изпращане на файл до всички клиенти в цикъл. След изпращане на данните на клиента е необходимо този случай да се визуализира на екрана:

Прогрес (fs.Position, fs.Size); // забавяне, в противен случай ще има загуба на пакети Sleep(SleepTime);

Тук използвам забавяне. при липсата му има ситуации на загуба на пакети. Например 100% от данните отиват на сървъра и само 99% идват на клиента. В тези случаи е необходимо да се добави контрол върху целостта на предаваните данни, но това е съвсем различна история.

След като изпратите част от файла, трябва да освободите паметта с помощта на функцията FreeMem. Възможно е да можете да разпределите памет само веднъж преди цикъла за изпращане и да я освободите, след като цикълът приключи, но това вече трябва да помислите.

procedure TForm1.ClientSocket1Read(Sender: TObject; // Socket: TCustomWinSocket); var nRead : Цяло число; rBuf : показалец; започнете . друго // режим на получаване на файл започнете повторете Socket.Lock; // заделяне на памет за получената част от данните GetMem(rBuf, bSize + 1); // четене на данни nRead = брой прочетени байтове nRead := Socket.ReceiveBuf(rBuf^, bSize); // ако нещо е било прочетено, тогава запис на данни във файл if nRead > 0 след това започнете fs.WriteBuffer(rBuf^, nRead); Gauge1.Progress := fs.Size; край; FreeMem(rBuf); Гнездо.Отключване; Application.ProcessMessages; до (nПрочетете 0 след това започнете fs.WriteBuffer(rBuf^,nПрочетете);

Ако се прочете поне 1 байт, тогава го записваме във файловия поток (във файл).

Както е посочено в ръководствата, при предаване на части от данни през сокет са възможни ситуации, когато част от данните пристига непроменена и евентуално нейната фрагментация или формиране на по-голяма част от данните. Тези. ако очакваме блок с размер bSize = 4000 байта на входа, тогава на практика могат да пристигнат 4500 байта. Експериментирах с извеждане на размера на получения фрагмент в дневника (RichEdit) и се оказа, че при твърдо кодиран размер от 8000 байта, след няколко секунди на изпращане на данни, той (размерът) може да се промени на 8189 байта. Следователно, за да не се ръководи от фиксиран размер на блока, четенето се извършва в цикъл.