-
Проблемма следующая: Есть TIdTCPClient на одной форме и TIdTCPServer на другой, устанавливаю подключение, вес в порядке... 1й случай: Клиент шлет серверу сообщения, шлет раз, шлет два.... все гут, делаю дисконнект, коннект, все окей опять шлю и все принимается все нормуль... 2й случай: клиент послал серверу сообщение, сервер его обработал, все гут, потом сервер шлет клиенту сообщение, клиент его принимает... все казалось бы Ок, но если после того, как сервер отправляет сообщение клиенту, и потом я делаю клиенту дисконнект, то ничё больше не работает, делаю клиентом повторный коннект, он пишет типа подсоединился, но сообщения больше не обрабатываются на сервере и сам сервер не может ниче послать грит ошибка "Connection Closed Grasfully" и все... как это решить... Помогите плиииз... P.S. использую Delphi 7 и Indy 10.1.5, отправка сообщений: Клиент: IdTCPClient1.Socket.WriteLn Сервер:TIdContext(IdTCPServer1.Contexts.LockList.Items[0]).Connection.Socket.Wri teLn
-
Кстати всем превет! Заранее спс...
-
У тебя ошибка в программе.
-
ВОт так обрабатываю сообщения на сервере:
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext); var recvfs: TFileStream; i, cp : byte; tmsg : TPackage; Buf : TIdBytes; begin tmsg.fHeader.totalSize := StrToInt64(AContext.Connection.Socket.ReadLn); AContext.Connection.Socket.ReadBytes( Buf , tmsg.fHeader.totalSize ); ZeroMemory(@tmsg,sizeof(tmsg)); tmsg.fHeader.cmd := Buf[0]; tmsg.fHeader.ParamCount := Buf[1];
Move ( Buf[2] , Cardinal(tmsg.fHeader.totalSize) , sizeof(cardinal) );
SetLength(tmsg.fHeader.ParamsLength , tmsg.fHeader.ParamCount); if tmsg.fHeader.ParamCount > 0 then Move( Buf[2 + SizeOf(cardinal)] , tmsg.fHeader.ParamsLength[0] , tmsg.fHeader.ParamCount * SizeOf(Cardinal) );
SetLength( tmsg.fData.Params , tmsg.fHeader.ParamCount ); if tmsg.fHeader.ParamCount > 0 then begin SetLength( tmsg.fData.Params[0] , tmsg.fHeader.Paramslength[0] ); cp := 2 + SizeOf(cardinal) + tmsg.fHeader.ParamCount * Sizeof(cardinal); Move( Buf[cp] , tmsg.fData.Params[0][1] , tmsg.fHeader.Paramslength[0] ); for i := 1 to tmsg.fHeader.ParamCount - 1 do begin inc( cp , tmsg.fHeader.Paramslength[i - 1] ); SetLength( tmsg.fData.Params[i] , tmsg.fHeader.Paramslength[i] ); Move( Buf[cp] , tmsg.fData.Params[i][1] , tmsg.fHeader.Paramslength[i] ); end; end; Memo1.Lines.Add('*********** We have a new message*******'); Memo1.Lines.Add(' Message CMD Code = ' + IntToStr(tmsg.fHeader.cmd)); Memo1.Lines.Add(' Message Params: ');
if tmsg.fHeader.paramCount>0 then for i := 0 to tmsg.fHeader.ParamCount - 1 do Memo1.Lines.Add(' ' + (tmsg.fData.Params[i])); Case tmsg.fHeader.cmd of CMD_CONNECTION_STR : Memo1.Lines.Add('We have a new connection...'); CMD_MESSAGE : Memo1.Lines.Add('This is a message'); CMD_FILE_UPLOAD :begin recvfs:= TFileStream.Create(ExtractFileName(tmsg.fData.Params[0])+'.tmp',fmCreate); AContext.Connection.Socket.ReadStream(recvfs,StrToInt(tmsg.fData.Params[1]),fals e); Memo1.Lines.Add('-----> New File upload complete...'); end; { CMD_DISCONNECT:begin AContext.Connection.Disconnect; end; {} end;
Memo1.Lines.Add('*********** End of new message*******'); end;
TPackageHeader = record cmd : byte; ParamCount : byte; totalSize : cardinal; ParamsLength : array of cardinal; end;
TPackageData = record Params:array of string; end;
TPackage = record fHeader : TPackageHeader; fData : TPackageData; end;
Сообщения сервер отправляет так: procedure TForm1.SendPackage(pcmd, pparamCount: byte; pparams: array of string); var tmsg : TPackage; i : integer; buf : TIdBytes; begin // // buf:=@tmsg; ZeroMemory(@tmsg,sizeof(tmsg)); tmsg.fHeader.cmd := pcmd; // tmsg.fHeader.totalSize := sizeof(tmsg.fHeader.cmd);
tmsg.fHeader.ParamCount := pparamCount; // tmsg.fHeader.totalSize := tmsg.fHeader.totalSize + sizeof(tmsg.fHeader.ParamCount);
// tmsg.fHeader.totalSize := tmsg.fHeader.totalSize + sizeof(tmsg.fHeader.totalSize);
SetLength(tmsg.fHeader.ParamsLength,pparamCount); // tmsg.fHeader.totalSize := tmsg.fHeader.totalSize + length(tmsg.fHeader.ParamsLength)*Sizeof(cardinal); SetLength(tmsg.fData.Params,pparamCount);
for i := 0 to pparamCount-1 do begin SetLength(tmsg.fData.Params[i],length(pparams[i])); Move(pparams[i][1],tmsg.fData.Params[i][1], length(pparams[i])); tmsg.fHeader.ParamsLength[i]:= length(tmsg.fData.Params[i]); tmsg.fHeader.totalSize:= tmsg.fHeader.totalSize + length(tmsg.fData.Params[i]) ; end;
tmsg.fHeader.totalSize := tmsg.fHeader.totalSize+ Sizeof(tmsg.fHeader.cmd)+ Sizeof(tmsg.fHeader.totalSize)+ Sizeof(tmsg.fHeader.ParamCount)+ Length(tmsg.fHeader.ParamsLength)*SizeOf(Cardinal);
SetLength(Buf, tmsg.fHeader.totalSize); Move(tmsg.fHeader.cmd, buf[0], 1); Move(tmsg.fHeader.ParamCount, buf[1], 1); Move(cardinal(tmsg.fHeader.totalSize), buf[2], sizeof(cardinal));
if pparamCount>0 then for i := 0 to pparamCount-1 do Move(tmsg.fHeader.ParamsLength[i], buf[6+i*Sizeof(Cardinal)], SizeOf(Cardinal));
if pparamCount>0 then begin Move(tmsg.fData.Params[0][1], buf[6+pParamCount*Sizeof(Cardinal)], length(tmsg.fData.Params[0])); for i := 1 to pparamCount-1 do Move(tmsg.fData.Params[i][1], buf[6+pParamCount*Sizeof(Cardinal)+Length(tmsg.fData.Params[i-1])], length(tmsg.fData.Params[i])); end; TIdContext(IdTCPServer1.Contexts.LockList.Items[0]).Connection.Socket.WriteLn(In tToStr(tmsg.fHeader.totalSize)); TIdContext(IdTCPServer1.Contexts.LockList.Items[0]).Connection.Socket.Write(Buf) ; end;
-
У клиента почти таже бадяга, но тока сообщения обрабатываются в таймере(как показано в Demosах):
procedure TForm1.Timer1Timer(Sender: TObject); var i:integer; s:string; begin if not IdTCPClient1.Connected then exit;
i:=IdTCPClient1.IOHandler.InputBuffer.Size; if i>0 then GetNewMessages; end;
GetNewMessages почти тот же код, что и у procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
-
Очевидных безобразий ы твоем коде явно не одно.
Взять хотя бы это:
> ZeroMemory(@tmsg,sizeof(tmsg));
С учетом типа поля Params:array of string обнуление этого поля недопустимо.
-
Ну про эту строчку вообще забыть можно... она сути проблеммы не меняет... Заменим её на tmsg.fHeader.cmd:=0; tmsg.fHeader.ParamCount:=0; tmsg.fHeader.totalSize:=0;
-
Воспользуйся встроенным отладчиком.
-
Я пользовался уже вчера им весь день, Buf заполняется идеально, tmsg заполняется идеально, дошел до самых низов Indy т.сказать все идеально, кол-во отправленных байт идеально, я уже от безысходности тут пишу, никогда нигде не отписывал... Если хочешь я тебе на мыло пришлю исходники, сам протестишь...???
-
> Если хочешь
Не хочу. Оно мне надо ?)
Факт-то налицо - отказ с диагностикой Connection Closed Grasfully возникает когда партнер по соединению закрывает его со своей стороны по своей же инициативе.
-
Праааально гришь, эта ошибка вылетает у TIdTCPServer значит клиент разорвал соединение, чтож все верно, но почиму она возникает только после того, как я с сервера пошлю клиенту сообщение???
Если Сервер ничего не посылает за сеанс клиенту, то клиент может коннектится и дисконнектится, и передавать серверу сообщения скока угодно раз... А стоит клиенту подключиться, серверу отправить сообщение, клиенту отключиться, клиенту подключиться, как УСЁ "Кирдык".... в чем прикол та??
-
> в чем прикол та?
Сказал ведь уже - у тебя ошибка в программе. Судя по [10] - в программе клиента.
-
Может я дисконнект у клиента неправильно делаю, может там что-ть ещё очищать надо?? ну эт савсем нонсенс был бы....
-
> PonosetcDM © (17.06.10 12:35) [12]
Таймер-то на стороне клиента нафих понадобился ?)
-
чтобы обрабатывать приход сообщений от сервера... можно и в отдельном потоке тоже самое делать, суть от этого не поменяется...
-
Клиент с сервером должен взаимодействовать по схеме "послал запрос - дождался и получил ответ на этот запрос"
Не вижу чтобы твой сервер в обработчике OnExecute посылал ответы клиенту на его запросы, хотя он обязан делать это именно там и нигде иначе.
-
Интересно, а если у меня на сервере произошло какое, то изменение, и я хачу сообщить об этом клиенту, чмне что прикажешь ждать, пока клиент не спросит у сервера, типа "все ли у тя в порядке?"... это же не прально... я бы хател сам уведомлять подключившихся клиентов о том что у мя что-то не так...чего я не магу сделать в OnExecute => должен быть способ это сделать...))
-
> чего я не магу сделать в OnExecute
Сделать это в OnExecute тебе запрещает религия ?
> а если у меня на сервере произошло какое, то изменение, > и я хачу сообщить об этом клиенту, чмне что прикажешь ждать, > пока клиент не спросит у сервера, типа "все ли у тя в порядке? > "
1. К. делает запрос "Сервер, я жду изменений" 2. С. отвечает на запрос "Нет изменений". 3. goto 1
или
1. К. делает запрос "Сервер, я жду изменений" 2. С. отвечает на запрос "На тебе изменеия". 3. К. получает и обрабатывает изменения . 4. goto 1
Именно по этим сценариям ты взаимодейстуешь прямо сейчас с delphimaster.ru-сервером и нос почему-то не воротишь)
-
Хорошо, пример такой: на сервере ясмотрю картинки, а на клиенте хачу чтобы мне приходило имя файла этой картинки.... Исходя из [17] выходит, что клиент должен постоянно опрашивать сервер, и получать от него это имя файла, и когда будет просматриваться другая картинка, я и получу это "другое" имя файла...
Но ведь по моему логичнее было бы просто при открытии очередной картинки сервером, посылать имя файла этой "другой" картинки клиенту...
-
> клиент должен постоянно опрашивать сервер
Для подавляющего большинства распределенных приложений это абсолютно нормальная и вполне оправданная логика.
|