Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Сети > как правильно отключить клиента


Автор: Coder 10.12.2006, 17:32
как правильно отключить клиента, а так же понять что все данные от него приняты?

// код клиента

Код

var
  lst : TStringList;
  ret : string;
begin
  lst:=TStringList.Create;
  lst.Add('login='+Edit1.Text);
  lst.Add('pwd='+Edit2.Text);
  lst.Add('ret_type='+'0');
  ret:=IdHTTP1.Post('127.0.0.1:80',lst);
  Memo1.Lines.Add(ret);
  lst.Free;
end;

// код сервера
procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  inp : string;
begin
  inp:=Socket.ReceiveText; // как определить все ли данные прочитаны ???

  Memo1.Lines.Add(inp);

  Socket.Close; // правильно ли так ???
end; 


проблема вот в чем, при попытке отослать данные серверу у клиента начинают вываливаться ошибки (но данные все же отсылаются - их видно в Мемо сервера): An existing connection was forcibly closed by the remote host.  и Connected Closed . Из текста ощибок подозреваю что дело в не правильном закрытии подключения.

Автор: Snowy 13.12.2006, 10:19
Ну ты ж с сокетом работаешь.
Всегда нужно приём/отправку ставить в try except.
Как на сервере, так и на клиенте.

Автор: Coder 13.12.2006, 12:01
Snowy, т.е. эти ошибки можно считать "нормальными"?

Автор: Snowy 13.12.2006, 14:05
Да, ибо обрыв связи - это исключительная ситация.
Её нужно обрабатывать.

Автор: x77 13.12.2006, 14:09
лучше пользоваться Indy, который сам контролирует целостность, и безо всяких исключений. а если уж делать на сокетах, то перед отправкой имеет смысл высчитать длину отправляемого сообщения и отправить серверу сначала эту длину. сервер её считывает и дальше продолжает читать, пока не вычитает всё либо не вылетит по тайму.

Автор: Coder 13.12.2006, 14:31
а как задать длину сообщения?

Автор: x77 13.12.2006, 14:34
Coder, Length (s) smile

Добавлено @ 14:45 
кусок из рабочего проекта.

клиент:
Код

const
  nCount = 32;
var
  Xml, s: widestring;
  Buf: array [0..nCount - 1] of char;
  i, Size, Count: integer;
  ss: TWinSocketStream;
begin
..
              cs.Active := TRUE; // открываем сокет (TClientSocket)
              cs.Socket.SendText (ChildNode.xml); // отправлям текст
              ss := TWinSocketStream.Create(cs.Socket, 60000); // создаём поток для чтения ответа от сервера
              try
                Xml := ''; // будущий ответ
                ss.WaitForData(10000); // ждём не дольше 10 секунд
                ss.Read(Size, 2); // читаем первые два байта
                Count := 0; 
                repeat
                  FillChar (Buf, nCount, #0); // обнуляем буфер
                  ss.WaitForData(10000); // ждём порцию данных
                  Count := Count + ss.Read(Buf, nCount); // считаем, сколько прочитано всего
                  Xml := Xml + Buf; // формируем результат
                until Count = Size; // и так пока всё не вычитаем.
              finally
                ss.Free;
              end;
..


сервер:
Код

procedure TService1.ssClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  InXml, OutXml: string;
  Size: integer;
begin
  InXml := Socket.ReceiveText;
  Request (InXml, OutXml);
  Size := LEngth (OutXml);
//  OutXml := 'Answering at ' + InXml;
  Socket.SendBuf(Size, 2);
  Socket.SendText(OutXml);
end;


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

Автор: x77 13.12.2006, 15:17
собственно, в такой раскладке - неблокирующий сервер + блокирующий клиент - в конце работы я даже не говорю Close или там Active := FALSE. ClientSocket и его поток для чтения создаются динамически, потом тупо освобождаются. никаких исключительных ситуаций нигде не возникает, уж не знаю почему.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)