Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Сети";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];

Вниз

Не понимаю - почему ошибка при копировании через ClientSocket?:(   Найти похожие ветки 

 
TankMan ©   (2005-03-23 12:15) [0]

Посмотрел в FAQ про передачу файлов через client-server Socket вот что получилось:

{Процедура на ClientSocket}
var sFile:TFileStream;
begin
sFile:=TFileStream.Create(eFileName.text,fmOpenReadWrite);
csClient.Socket.SendText("@-"+Edit2.text+"-@#-"+inttostr(sFile.Size)+"-#");
csClient.Socket.SendStream(sFile);
sleep(100);
sFile.Free;
csClient.Close;

{Прием на ServerSocket}

procedure TForm1.ssServerClientRead(Sender: TObject;
 Socket: TCustomWinSocket);
var command,param:string;
l: DWORD;
buf: PChar;
src: TFileStream;
begin
if ReceiveFile then
begin
 l := Socket.ReceiveLength;
 GetMem(buf,l+1);
 Socket.ReceiveBuf(buf,l);
 if not fileExists(ExtractFilePath(ParamStr(0))+"vot.upd") then
 src:=TFileStream.Create(ExtractFilePath(ParamStr(0))+"vot.upd",fmCreate)
 else src:=TFileStream.Create(ExtractFilePath(ParamStr(0))+"vot.upd",fmOpenReadWrite);
 src.Seek(0,soFromEnd);
 src.WriteBuffer(buf,l);
 FreeMem(buf);
 Application.ProcessMessages;
 src.Free;
 LenghtofFile:=LenghtofFile-l;
 if LenghtofFile=0 then begin ReceiveFile:=false;ShowMessage("File is received");end;
 exit;
end;  //   }
if ExtractParamCommand(Socket.ReceiveText,command,param) then
Memo1.Lines.Add(Socket.RemoteAddress+":"+Command+" - "+Param)
else Memo1.Lines.Add(Socket.RemoteAddress+":"+Param);
if command="update" then begin ReceiveFile:=true; LenghtofFile:=strtoint(Param);end; //}


Вобщем суть такова - клиент в начале посылает строку с коммандой и параметром а сервер приняв комманду, узнает не update-ли это, и если так то (как я задумал :) ) начинает прием файла...
Но тут то и проблема, почему-то выбрав файл в клиенте , я нажав отправить на строке
csClient.Socket.SendStream(sFile);
Выдается ошибка stack overflow, или так же выдавалась ошибка EPrivilege :(, я бы понял, если бы я был не под администратором, но почемуж он выдает ошибку :( не понимаю :(
Ах да забыл сказать, для удобства и клиент и сервер находится на одном компе на клиенте стоит Address:="127.0.0.1", соединяется нормально...
Может кто знает более надежный/удобный способ/алгоритм передачи через socket?


 
TankMan ©   (2005-03-23 12:17) [1]

И еще забыл сказать, что на строке
FreeMem(buf);
В процедуре приема данных почему-то выдается ошибка access violation, хотя GetMem выдает положительный результат :(


 
Digitman ©   (2005-03-23 12:59) [2]

куча грубых ошибок ... и в коде сервера и в коде клиента ..

по поводу клиента - начни с внимательного чтения замечаний в станд.справке к методу SendStream


 
TankMan ©   (2005-03-23 13:26) [3]

>>Digitman
Мдаа, вот потом пологайся на статьи на солидных порталах...
http://delphi.mastak.ru/articles/socksrv/index.html
И всетаки ошибки остались, которые я не могу исправить :(


 
Digitman ©   (2005-03-23 14:28) [4]


> TankMan ©   (23.03.05 13:26) [3]


бездумно сдирать код я тебе не советую.
ВНЕ зависимости откуда ты его содрал - хоть с "солидного портала" хоть с убогого ..

статейный код, где бы и каким бы он ни был, приводится не для бездумного сдирания, а для детального анализа и адаптации к КОНКРЕТНОЙ ситуации и требованиям.


> И всетаки ошибки остались, которые я не могу исправить


для начала приведи фрагмент, где ты исправил уже упомянутые мной "ошибки"


 
TankMan ©   (2005-03-24 07:30) [5]

ХА!! :)
Я тут почитал архивы :), я смотрю - я далеко не первый кто воспользовался этой статьей, и я далкео не первый кому ты пытался указать на ошибки конкретно не тыкая носом :),
но статью удалили совсем недавно, кажется :)...

А исправил я вот что - во первых в клиенте убрал sFile.Free;и csClient.Close;
А в сервере

 i:=Socket.ReceiveBuf(buf^,l);
 if not fileExists(ExtractFilePath(ParamStr(0))+"vot.upd") then
 src:=TFileStream.Create(ExtractFilePath(ParamStr(0))+"vot.upd",fmCreate)
 else src:=TFileStream.Create(ExtractFilePath(ParamStr(0))+"vot.upd",fmOpenReadWrite);
 src.Seek(0,soFromEnd);
 src.WriteBuffer(buf^,i);
 FreeMem(buf);
 src.Free;
 LenghtofFile:=LenghtofFile-i;
 if LenghtofFile=0 then begin ReceiveFile:=false;ShowMessage("File is received");end
 else Memo1.Lines.Add("Осталось :"+inttostr(LenghtofFile));

Но тем неменее у меня ошибка...
Файл - плейлист (для примера), который я пересылаю, занимает 65кб а пересылается почему-то 57-59кб, т.е. я так понимаю - последний пакет не доходит... а почему :(


 
Digitman ©   (2005-03-24 08:14) [6]


> Но тем неменее у меня ошибка


какая ? на какой строчке ?


 
TankMan ©   (2005-03-25 07:12) [7]

Тут получается вообще не конкретная ошибка, а общая...
Файл посылается - клиент не выдает никаких ошибок, сервер тоже ничего не выдает, но файл отосланный клиентом становиться короче на 7кб...а примерно столько я понимаю и "весит" один пакет, значит он не доходит, вот не могу понять почему?

З.Ы.
Но у меня вопрос, а почему нужно ставить "^"? Я так понимаю это передача не переменной, а указателя, так? но в описании ReceiveBuf ни слова про указатели я не встретил...может это само собой подразумевалось? А я и не знаю :(


 
Digitman ©   (2005-03-25 08:17) [8]


> не конкретная ошибка, а общая


приводи полный код клиента и сервера с учетом уже сделанных тобой коррекций


> почему нужно ставить "^"?


формальный параметр, задающий буфер, в ф-ции SendBuf объявлен как

var Buf

это означает, что фактический параметр м.б. нетипизированным и передается не по значению, а по ссылке

т.о., если у тебя факт.параметр объявлен как

buf: PChar

в ф-цию будет передан адрес переменной buf, а не ее содержимое (в ней хранится указатель на собственно буфер)

поэтому и требуется т.н. "разыменование переменной" - увидев галку компилятор передаст в ф-цию в качестве ссылки именно то, что лежит в указательной переменной, а не адрес самой этой переменной ... что собссно и требуется ...


 
TankMan ©   (2005-03-25 09:52) [9]

Вот клиента кусок :)

procedure TForm1.Button2Click(Sender: TObject);
var sFile:TFileStream;
begin
sFile:=TFileStream.Create(edit3.text,fmOpenReadWrite);
csClient.Socket.SendText("@-"+Edit2.text+"-@#-"+inttostr(sFile.Size)+"-#");
csClient.Socket.SendStream(sFile);
end;


А вот сервера кусок:

procedure TForm1.ssServerClientRead(Sender: TObject;
 Socket: TCustomWinSocket);
var command,param:string;
l: DWORD;
i:integer;
buf: PChar;
src: TFileStream;
begin
if ReceiveFile then
begin
 l := Socket.ReceiveLength;
 GetMem(buf,l+1);
 i:=Socket.ReceiveBuf(buf^,l);
 if not fileExists(ExtractFilePath(ParamStr(0))+"vot.upd") then
 src:=TFileStream.Create(ExtractFilePath(ParamStr(0))+"vot.upd",fmCreate)
 else src:=TFileStream.Create(ExtractFilePath(ParamStr(0))+"vot.upd",fmOpenReadWrite);
 src.Seek(0,soFromEnd);
 src.WriteBuffer(buf^,i);
 FreeMem(buf);
 src.Free;
 LenghtofFile:=LenghtofFile-i;
 if LenghtofFile=0 then begin ReceiveFile:=false;ShowMessage("File is received");end
 else Memo1.Lines.Add("Îñòàëîñü :"+inttostr(LenghtofFile));
 exit;
end;
if ExtractParamCommand(Socket.ReceiveText,command,param) then
Memo1.Lines.Add(Socket.RemoteAddress+":"+Command+" - "+Param);
if command="update" then begin ReceiveFile:=true; LenghtofFile:=strtoint(Param);exit;end; //}
end;


ХМ... сейчас еще раз попробовал запустить и проверить - выдал - что все нормально переписалось, я уж обрадовался, попробовал еще раз - и опять - не дописывает последние 4-7 кб в не зависимости от размера файла (качал от 65кб до 1100кб)... не понимаю...


 
Digitman ©   (2005-03-25 10:26) [10]

вот с чего ты взял, что строка, переданная вызовом SendText(), придет целиком, и ты получишь ее вызовом ReceiveText() именно в том виде, в каком отправлял ?

если ты передал строку и следом же начал передавать стрим, то на принимающей стороне за одно событие OnRead() ты можешь получить все что угодно : и строку целиком, и ее часть, и строку плюс кусок стрима ... никаких предположений насчет сооответствия передаваемого и принимаемого "пакетов" нет и быть не может - это же поток !

чтобы передать строку, нужно передать сначала ее длину (например, integer-значение, т.н. ПРЕФИКС), а затем собственно строковые данные .. принимающая же сторона читает сначала длину (те самые 4 байта, что составляют integer-значение), выделяет память под строку, а затем за одно или более событий OnRead читает собственно поступающие последовательные фрагменты строковых данных, аккумулируя их и ведя подсчет оставшихся (еще не полученных) стр.данных ... как только сч-к принятых стр.данных будет равен ПРЕФИКСУ, можно считать что строка принята целиком, ни больше ни меньше, и только тогда анализировать содержимое строки и переключаться если нужно на прием передаваемых следом франментов стрима, точно так же аккумулируя их и ведя сч-к принятых байт


 
Slym ©   (2005-03-25 11:12) [11]

Почему все новички думают если они отправили 2 строки... они и получат 2 строки, а не одну и ли 3. Сокет - это поток данных, и разбивать эти данные на строки/стремы должен сам программист встявляя в поток данных метки начала/конца лексемы ее длинну (если надо)... За тебя твой протокол взаимодействия клиента с сервером никто не напишет...

еслиб делал я то:
1. Делал сервер в блокирующем режиме... (так гораздо удобнее и надежней)
2. отправлял заголовок с маркером конца (например #0, или #13#10)
"@-FileName-@#-12563-#"+#0
потом читал заголовок пока не науду маркер конца...
3. Апосле читаю переданые данные.


 
TankMan ©   (2005-03-25 12:04) [12]

А не могли бы вы привести пример работы в бокирующем режиме?


 
Slym ©   (2005-03-25 12:19) [13]

примерно так
Сервер

unit SocketThread;

interface
uses Windows,ScktComp,Classes;

const LogMessageStr="%s: raised exception %s with message %s";

type
 TSocketThread=class(TServerClientThread)
 private
   ln:string;
   procedure Work;
 protected
   procedure ClientExecute; override;
 end;

implementation
uses Form,SysUtils;

procedure Writeln(Stream:TStream;const Data:string);
begin
 Stream.WriteBuffer(PChar(Data)^,length(Data));
 Stream.WriteBuffer(#13#10,2);
end;

function ReadLn(Stream:TStream):string;
const cCR = #10; cLF = #10; cEOF = #26;
var Ch:Char;
begin
 result:="";
 while Stream.Read(Ch,1)>0 do
 begin
   if Ch=cLF then break;
   if Ch=cEOF then break;
   if Ch<>cCR then
   begin
     result:=result+Ch;
     continue;
   end;
   if Stream.Read(Ch,1)=0 then break;
   if Ch=cLF then break;
   if Ch=cEOF then break;
   result:=result+cCR+Ch;
 end;
end;

{ TSocketThread }

procedure TSocketThread.ClientExecute;
var Stream:TWinSocketStream;
 dos:boolean;
begin
 dos:=true;
 try
   Stream:=TWinSocketStream.Create(ClientSocket, 60000);
   try
     while (not Terminated) and ClientSocket.Connected do
     begin
       if Stream.WaitForData(60000) then
       begin
         ln:=ReadLn(Stream);//Сдеся заголовок с маркером конца #13#10
         
         src:=TFileStream.Create(ExtractFilePath(ParamStr(0))+"vot.upd",fmCreate);
          src.Seek(0,soFromEnd);
         src.ReadFromStream(Stream);
         ClientSocket.Close
       end else
        ClientSocket.Close;
     end;
   finally
     Stream.Free;
   end;
 except
 end;
end;

procedure TSocketThread.Work;
begin
 Form1.Speak(ln);
end;


Событие GetThread у ServerSocket:
procedure TForm1.ServerSocketGetThread(Sender: TObject;
 ClientSocket: TServerClientWinSocket;
 var SocketThread: TServerClientThread);
begin
 SocketThread:=TSocketThread.Create(false,ClientSocket);
end;


 
TankMan ©   (2005-03-25 12:20) [14]

Т.е. я хотел спросить, а как принципиально структура кода (приема/передачи) изменится перейди я на блокирующий режим?


 
TankMan ©   (2005-03-25 12:34) [15]

ОО :) Пока писал небыло :)
Ага...надо будет разобраться...
А src.ReadFromStream(Stream); откуда?
У меня в TFileStream такого нет...


 
Slym ©   (2005-03-25 12:55) [16]

И правда нету... а реализовать проблема? Смотри TMemoryStream.ReadFromStream


 
TankMan ©   (2005-03-25 13:01) [17]

Ах да :) Буду смотреть щас...


 
atruhin ©   (2005-03-25 15:49) [18]

В любом случае, если это не пример, нужно обробатывать все ошибки, как правило их обработка в сокетах, занимает 50-70% кода, но это единственный вариант безглючной работы


 
TankMan ©   (2005-03-28 06:46) [19]

У меня вопрос...
Я так понимаю в Readln
const cCR = #10; cLF = #10; cEOF = #26
cLF=#13 или нет?
А LoadFromBuffer в MemoryStream я так понял сводятся конкретно до ReadBuffer(Pointer(Stream),Stream.Size);?
Так и написал... а посылка файла никак не изменяется в клиенте?
А то он мне ошибку выдает stack overflow....
Еще хотелось бы узнать, а как обработать ошибку при попытки подключения, если сервер не найден, onerror не реагирует, except тоже не сдерживает - выскакивает ошибка "..machine actively refused it (10061)..." и усе, а когда сервак запущен,то все нормально...


 
TankMan ©   (2005-03-28 07:16) [20]

Посмотрел пример в инете - исправил клиент - тот же эффект :(
Клиент выглядит так:

sFile:=TFileStream.Create(edit3.text,fmOpenReadWrite);
csClient.Socket.SendStream(sFile);
Sock:=TWinSocketStream.Create(csClient.Socket,10000);
Sock.CopyFrom(sFile,sFile.Size);
except
raise
end;


 
TankMan ©   (2005-03-29 09:23) [21]

А никто не видел случайно статью на русском, про все это дело, а то у меня в 3х книгах вообще ничего про передачу данных через сокет не сказано :(



Страницы: 1 вся ветка

Форум: "Сети";
Текущий архив: 2005.06.29;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.195 c
14-1117571809
NailMan
2005-06-01 00:36
2005.06.29
Любитенлям Star Wars


4-1115318045
bc0113
2005-05-05 22:34
2005.06.29
FreeLibrary


1-1117875729
Masta Hookah
2005-06-04 13:02
2005.06.29
COPY FILE


1-1118130236
makle
2005-06-07 11:43
2005.06.29
TreeView. Количество вложенных уровней у нода


3-1116321269
_Max
2005-05-17 13:14
2005.06.29
DBGrid - строки разной высоты





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский