Почему несколько блоков при передаче по сокету могут объединяться в один
|
Скорость передачи между двумя и более пользователями Intеrnеtа при обрыве связи внезапно возрастает до 2 мегаматов в секунду.
|
Итак, во-первых, надо заметить, что посылаемые через сокет данные могут не только
объединяться в один блок, но и разъединяться по нескольким блокам. Дело в том, что сокет -
обычный поток, но в отличие, скажем, от файлового (TFileStream), он передает данные медленнее
(сами понимаете - сеть, ограниченный трафик, и т.д.). Именно поэтому две команды:
ServerSocket1.Socket.Connections[0].SendText('Hello, ');
ServerSocket1.Socket.Connections[0].SendText('world!');
совершенно идентичны одной команде:
ServerSocket1.Socket.Connections[0].SendText('Hello, world!');
И именно поэтому, если Вы отправите через сокет файл, скажем, в 100 Кб, то тому, кому Вы
посылали этот блок, придет несколько блоков с размерами, которые зависят от трафика и
загруженности линии. Причем, размеры не обязательно будут одинаковыми. Отсюда следует, что
для того, чтобы принять файл или любые другие данные большого размера, Вам следует принимать
блоки данных, а затем объединять их в одно целое (и сохранять, например, в файл). Отличным
решением данной задачи является тот же файловый поток - TFileStream (либо поток в памяти -
TMemoryStream). Принимать частички данных из сокета можно через событие OnRead
(OnClientRead), используя универсальный метод ReceiveBuf. Определить размер полученного блока
можно методом ReceiveLength. Также можно воспользоваться сокетным потоком (см. статью про
TClientSocket). А вот и небольшой примерчик (приблизительный):
{Прием файла через сокет}
procedure TForm1.ClientSocket1Read(Sender: TObject;
Socket: TCustomWinSocket);
var l: Integer;
buf: PChar;
src: TFileStream;
begin
{Записываем в l размер полученного блока}
l := Socket.ReceiveLength;
{Заказываем память для буфера}
GetMem(buf,l+1);
{Записываем в буфер полученный блок}
Socket.ReceiveBuf(buf,l);
{Открываем временный файл для записи}
src := TFileStream.Create('myfile.tmp',fmOpenReadWrite);
{Ставим позицию в конец файла}
src.Seek(0,soFromEnd);
{Записываем буфер в файл}
src.WriteBuffer(buf,l);
{Закрываем файл}
src.Free;
{Освобождаем память}
FreeMem(buf);
end;
|
|