WinSock получить PChar

dizpers
Дата: 08.05.2011 17:13:18
Здравствуйте!
Возникла такая проблема. Есть клиентское и серверное приложение, написанное на Delphi с использованием WinSock. Есть код отправки сообщения на клиенте:

+
function TNet.SendText(const text : PChar) : boolean;
Var
  zz : Integer;
begin
  Result := false; // пока еще ничего не смогли отправить


  zz := 23;
  if (send(sServerListen, text^, SizeOf(Char)*StrLen(text), 0) = SOCKET_ERROR) then
    begin
      actError.Tag := 4;
      actError.Execute;
      exit; // не смогли отправить сообщение, вывели ошибку и тут нам больше делать нечего:)
    end;

  Result := true;
end;


Теперь пишу код приема этого сообщения. И возникают проблемы - кол-во принятых байт я могу получить, а саму строку - нет. Вот последнее что написал:

+
procedure TReadThread.Execute;
Var
  temp : PChar;
  iRead, len : Integer;
begin
  try
    FText := string('');
    temp := string('');
    len := SizeOf(Char)*512;

    iRead := recv(FSocket, temp, len, 0);

    while (iRead>0) do
      begin
        FText := pchar(string(FText) + string(temp));
        iRead := recv(FSocket, temp, len, 0);
      end;

  except
    on E : Exception do
      frmMain.meLog.Lines.Add(E.Message);
  end;
end;


Подозреваю, что надо было выделить память под PChar ... но запутался - не пойму как правильно принять строку в PChar - подскажите как правильно сделать прием строки. Заранее спасибо!
wellwell
Дата: 08.05.2011 17:43:16
dizpers
Подозреваю, что надо было выделить память под PChar ... но запутался - не пойму как правильно принять строку в PChar - подскажите как правильно сделать прием строки. Заранее спасибо!


OMG!

var
 Buffer : array[0..$1000] of char;

...
ZeroMemory(@Buffer,SizeOf(Buffer));
BytesRead := recv(Socket, Buffer, SizeOf(Buffer), 0);
...
ShowMessage(Buffer);
dizpers
Дата: 08.05.2011 18:05:36
1. А сразу в PChar считывать нельзя? Если можно, то как реализовать?

2. Если получать данные в буффер - то как их можно запихивать в PChar переменную?
dizpers
Дата: 08.05.2011 23:33:21
Вобщем проблема с передачей строки разрешилась. Решил проблему влоб - передаю помимо самой строки и ее размер. Вот исходники:

+=отправка
function TNet.SendText(const text : PChar) : boolean;
Var
  zz : Integer;
begin
  Result := false; // пока еще ничего не смогли отправить

  zz := StrLen(text)*SizeOf(Char) + 2;
  if (send(sServerListen, zz, SizeOf(zz), 0) = SOCKET_ERROR) then
    begin
      actError.Tag := 4;
      actError.Execute;
      exit; // не смогли отправить сообщение, вывели ошибку и тут нам больше делатьнечего:)
    end;

  if (send(sServerListen, text^, zz, 0) = SOCKET_ERROR) then
    begin
      actError.Tag := 4;
      actError.Execute;
      exit; // не смогли отправить сообщение, вывели ошибку и тут нам больше делатьнечего:)
    end;

  Result := true;
end;


+=прием сообщения
procedure TReadThread.Execute;
Var
  iRead, len : Integer;
begin
  try
    iRead := recv(FSocket, len, SizeOf(len), 0);
    Getmem(FText, len);
    iRead := recv(FSocket, FText^, len, 0);
  except
    on E : Exception do
      frmMain.meLog.Lines.Add(E.Message);
  end;
end;


Вроде бы все работает - отсылает и принимает:) Если что-то не совсем корректно написал - поправьте пожалуйста:)

PS

И еще такой вопрос. Правда не совсем в тему сетевого программирования на Delphi и WinSock. Вопрос вот в чем. Отправка строки это конечно хорошо. Но как лучше организовать протокол работы самого чата? Первое что приходит в голову - придумать своего рода команды типа AUTH, MSG, PRIVATEMSG, QUIT - передавать все это дело в строке PChar и на сервере уже парсить строку и выполнять нужные действия... Тут опять возникает вопрос - если я скажем будут отсылаться такие команды:

1. USER admin
2. PASSWORD coolpass

То гарантирует ли TCP мне порядок доставки этих сообщений всегда? То есть я буду уверен, что PASSWORD отправленный - это именно пароль пользователя admin а не какого-то другого. И такой вопрос. Посмотрел для примера RFC IRC клиента и сервера - там ограничение на длину сообщения включая команду - 512 байт. А у меня получается ограничения как такогового нет - отправляю строку PChar - в чем преимущества и недостатки ограничения на размер сообщения?
wellwell
Дата: 09.05.2011 04:45:23
Код совершенно ненадежный и с кучей ошибок

1. send может вернуть число отправленных байт, меньшее чем размер данных переданных ему
2. В принимающем потоке все вообще плохо - утечка памяти на каждую операцию (нет FreeMem), не видно никакой проверки что возвращается из recv, доступ к VCL без синрохонизации гарантирует странные случайные глюки...

3. TCP гарантирует порядок
4. Вот представь я подключился к твоему серверу и сказал: а счас я отправлю строку 2GB длиной. Дальше чем догадаешься?
dizpers
Дата: 09.05.2011 12:07:29
wellwell

Спасибо за ответ! С размером сообщения начинаю понимать. Но для защиты от такого я и подумал о том, чтобы сначала передавать размер сообщения, и если размер меня устраивает - то пропускать пакет, если нет - то не пускать. Хотя сейчас я уже понимаю, что ничто не мешает направить ложную длину сообщения... поэтому лучше действительно считывать пакет скажем по 512 байт и если размер получаемой структуры переваливает за установленную границу, то фильтровать такой пакет. Верно мыслю?

И еще вопрос - когда говорят о формировании пакета в рамках прикладного протокола - скажем того же IRC, то не имеется же в виду ручное формирование IP-пакета? Как я понял имеется в виду передача некой структуры данных, по типу такой:

type
	TMyPacket = record
		len 	: Integer;  //  длина сообщения
		com 	: Byte;  // таким вот образом как я понял реализуется индексация команда
		msg	: PChar;  //  а здесь собственно передаваемые данные
	end;

Ла - и про индексацию команд. Так называемые human-readable протоколы сейчас актуальны? Или лучше провести соответствии между определенной командой и числовым значением?

По поводу утечки памяти - я освобождаю память после завершения работы потока - это корректно? По поводу send не понял - когда может вернуть не правильное число байт?