Модераторы: Snowy, Poseidon, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> WinSock и Нулевые символы? Как получить необреззаный пакет? 
:(
    Опции темы
MaDCoD
  Дата 17.11.2008, 11:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 8.5.2006

Репутация: нет
Всего: нет



У меня возник вопрос:
Я получаю странички через WinSock, обчным GET запросом. (Через Send) Всё нормально получается, пока не встретиться нулевой символ в приходящем пакете. Я так понял WinSock решает, что это конец данных и перестаёт принимать данные. Эта же проблема актуальна например при получении картинок через WinSock, так как там часто встречаются эти 00h..
Собстно сам вопрос, кто-нибудь уже сталкивался с такой ситуацией и как её можно исправить?

Это сообщение отредактировал(а) MaDCoD - 17.11.2008, 11:21
PM MAIL   Вверх
Matematik
Дата 17.11.2008, 11:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1027
Регистрация: 11.3.2006

Репутация: 24
Всего: 50



> Я так понял WinSock решает, что это конец данных и перестаёт принимать данные.

Неверно.

> Я получаю странички через WinSock, обчным GET запросом

Имеется в виду HTTP протокол? 
Там много нюансов с передачей данных.

Вобщем без кода помочь не получиться.


PM MAIL WWW ICQ   Вверх
MaDCoD
Дата 17.11.2008, 21:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 8.5.2006

Репутация: нет
Всего: нет



Да, конечно по HTTP передаю, вот пример кода:
Основная процедура передачи:
Код

CreateSock(S);
strpcopy(buf,'GET /index.php HTTP/1.1'#13#10
                  +'Host: site.net'#13#10#13#10
                  );
send(S,buf,strlen(buf),0);
RecBuf(S,buf);

Функция:
Код

function RecBuf(var S:TSocket;var buf:TBuf):integer;
var n,buflen:integer;
    FDSet:TFDSet;
    t:TTimeVal;
begin buflen:=0;
      FD_Zero(FDSet);
      t.tv_sec:=15;
      t.tv_usec:=0;
      repeat
    FD_Set(S,FDSet);
    n:=Select(0,@FDSet,nil,nil,@t); 
    if FD_IsSet(S,FDSet) then begin
      n:=Recv(S,buf[buflen],$FFFF,0);
      if n>=0 then inc(buflen,n);
      buf[buflen]:=#0
    end
      until n<=0;
      Shutdown(S,SD_BOTH);
        CloseSocket(S); 
      result:=buflen
end;

Создание сокета:
Код

procedure CreateSock(var S:TSocket);
var addr:TSockAddr;
ip:string;
begin S:=Socket(AF_Inet,Sock_Stream,IPProto_TCP);
      if S=Invalid_Socket then begin   
    MessageBox(0,'Ошибка!','Ошибка',mb_ok);
 S:=0;
 exit;
      end;
      addr:=Adr(InAddr_Any,0);
      setsockopt(s, SOL_SOCKET, SO_REUSEADDR, pchar($0000), sizeof($0000));
      setsockopt(s, SOL_SOCKET, SO_LINGER, pchar($0000), sizeof($0000));
     Err(Bind(S,@addr,SizeOf(addr)));
      ip:='127.0.0.1'; 
      addr:=Adr(Inet_Addr(PAnsiChar(ip)),strtoint('80'));
      if Connect(S,@addr,SizeOf(TSockAddr))<>0 then begin
      Shutdown(S,SD_BOTH);
        CloseSocket(S);
      S:=0;
      exit;
      end;
end;


ip, ставится принадлежащий сайту естественно
И ещё смотря через сниффер, отлавливаю весь пакет который приходит, вместе с нулевыми символами, но после RecBuf(S,buf); Загружаю ответ в поток с последующим сохранением в файл или в мемо с предварительным преобразованием в строку через StrPas, и там и там пакет получается обрезанным после нулевых символов.
PM MAIL   Вверх
Virtuals
Дата 18.11.2008, 06:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 476
Регистрация: 27.11.2006

Репутация: 2
Всего: 11



MaDCoD, 
ничего в голову не приходит?
Цитата

The fundamental types PAnsiChar and PWideChar represent pointers to AnsiChar and WideChar values, respectively. The generic PChar represents a pointer to a Char (that is, in its current implementation, to an AnsiChar). These character pointers are used to manipulate null-terminated strings. (See Working with null-terminated strings.)

избегай использовать PChar и просто_стринг, лучше 
array of char
а еще лучше
array of Byte smile 

Это сообщение отредактировал(а) Virtuals - 18.11.2008, 06:19
PM MAIL ICQ   Вверх
MaDCoD
Дата 18.11.2008, 08:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 8.5.2006

Репутация: нет
Всего: нет



Virtuals,
Так строки у меня практически нигде и не используются,
buf объявлен как TBuf, который array[0..131070]of char,
опять же при загрузке например в поток не должно препятствовать наличие нулевых символов ведь так? :
Код

    ms:= TMemoryStream.Create;
    ms.Write(buf,strlen(buf));
    ms.Position:=0;
    ms.SaveToFile('1.txt');
    ms.Free;


Ни как не пойму в каком месте, прекращается приём пакета..

Это сообщение отредактировал(а) MaDCoD - 18.11.2008, 08:31
PM MAIL   Вверх
MetalFan
Дата 18.11.2008, 08:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Аццкий Сотона
****


Профиль
Группа: Комодератор
Сообщений: 3815
Регистрация: 2.10.2006
Где: Moscow

Репутация: 14
Всего: 128



MaDCoD, 
а можно код в более читаемо отформатировать? а то не читается никак)



--------------------
There are always someone smarter than you...
PM MAIL   Вверх
MaDCoD
Дата 18.11.2008, 09:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 8.5.2006

Репутация: нет
Всего: нет



MetalFan, так?))
Код

//Cutted
//type TBuf=array[0..131070]of char;

procedure CreateSock(var S:TSocket);
var addr:TSockAddr;
ip:string;
begin S:=Socket(AF_Inet,Sock_Stream,IPProto_TCP);
      if S=Invalid_Socket then begin   
    MessageBox(0,'Ошибка!','Ошибка',mb_ok);
 S:=0;
 exit;
      end;
      addr:=Adr(InAddr_Any,0);
      setsockopt(s, SOL_SOCKET, SO_REUSEADDR, pchar($0000), sizeof($0000));
      setsockopt(s, SOL_SOCKET, SO_LINGER, pchar($0000), sizeof($0000));
     Err(Bind(S,@addr,SizeOf(addr)));
      ip:='127.0.0.1'; 
      addr:=Adr(Inet_Addr(PAnsiChar(ip)),strtoint('80'));
      if Connect(S,@addr,SizeOf(TSockAddr))<>0 then begin
      Shutdown(S,SD_BOTH);
        CloseSocket(S);
      S:=0;
      exit;
      end;
end;

function RecBuf(var S:TSocket;var buf:TBuf):integer;
var n,buflen:integer;
    FDSet:TFDSet;
    t:TTimeVal;
begin buflen:=0;
      FD_Zero(FDSet);
      t.tv_sec:=15;
      t.tv_usec:=0;
      repeat
    FD_Set(S,FDSet);
    n:=Select(0,@FDSet,nil,nil,@t); 
    if FD_IsSet(S,FDSet) then begin
      n:=Recv(S,buf[buflen],$FFFF,0);
      if n>=0 then inc(buflen,n);
      buf[buflen]:=#0
    end
      until n<=0;
      Shutdown(S,SD_BOTH);
        CloseSocket(S); 
      result:=buflen
end;

procedure TForm1.XPButton1Click(Sender: TObject);
//Cutted - объявление типов и задание исходных значений
//var buf:TBuf;
CreateSock(S);
strpcopy(buf,'GET /index.php HTTP/1.1'#13#10
                  +'Host: site.net'#13#10#13#10
                  );
send(S,buf,strlen(buf),0);
RecBuf(S,buf);
ms:= TMemoryStream.Create;
ms.Write(buf,strlen(buf));
ms.Position:=0;
ms.SaveToFile('1.txt');
ms.Free;
{либо
page:=StrPas(buf);
Memo1.Text:=page;}
//Cutted - продолжение обработки

PM MAIL   Вверх
Qu1nt
Дата 18.11.2008, 15:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 2
Всего: 50



Код

program wiki;

{$APPTYPE CONSOLE}

uses
  WinSock, Windows;

const
  Host = 'ru.wikipedia.org';

var
  Sock : TSocket;
  Addr : TSockAddr;
  HostEnt : PHostEnt;
  WSAData : TWSAData;
  Source : string;
  Buf  : array [0..1023] of Char;
  Res  : Integer;
  Data : string = 'GET /wiki/HTTP HTTP/1.1' + #13#10 +
         'Host: ' + Host + #13#10 +
         'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)' + #13#10 +
         'Accept: text/html' + #13#10 +
         'Connection: close' + #13#10#13#10;

begin
  if WSAStartup($101, WSAData) <> 0 then
    Exit;
  WriteLn('Uses WinSock...');
  Sock := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  if Sock = INVALID_SOCKET then
  begin
    Writeln('Can not create socket. Code: ', WSAGetLastError());
    Exit;
  end;
  Writeln('Searching for: ', Host);
  HostEnt := gethostbyname(PChar(Host));
  if HostEnt = nil then
  begin
    Writeln('Unable to find host. Code: ', WSAGetLastError());
    Exit;
  end;
  with Addr do
  begin
    sin_family := AF_INET;
    sin_port   := htons(80);
    sin_addr   := PInAddr(HostEnt^.h_addr_list^)^;
  end;
  Writeln('Host found: ', inet_ntoa(Addr.sin_addr));
  if connect(Sock, Addr, SizeOf(TSockAddr)) = SOCKET_ERROR then
    if WSAGetLastError() <> WSAEWOULDBLOCK then
    begin
      Writeln('Unable to connect. Code: ', WSAGetLastError());
      Exit;
    end;
  Writeln('Connected.');
  Res := send(Sock, Data[1], Length(Data), 0);
  if Res = SOCKET_ERROR then
  begin
    Writeln('Uable to send data. Code: ', WSAGetLastError());
    Exit;
  end;
  repeat
    Res := recv(Sock, Buf, 128, 0);
    if Res = SOCKET_ERROR then
    begin
      Writeln('Unable to receive data. Code: ', WSAGetLastError());
      Exit;
    end;
    if Res > 0 then
      Source := Source + Copy(Buf, 0, Res);
  until Res <= 0;
  WriteLn;
  WriteLn(Source);
  WriteLn;
  CloseSocket(Sock);
  Writeln('End.');
  WSACleanup;
  Readln;
end.


Это сообщение отредактировал(а) Qu1nt - 18.11.2008, 15:22
PM MAIL   Вверх
MaDCoD
Дата 18.11.2008, 17:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 14
Регистрация: 8.5.2006

Репутация: нет
Всего: нет



Qu1nt,
другой выход тоже выход))
Но мне интересно, что именно в моём коде не позволяет загрузить данные после нулевого символа. Виноват 99% он, т.к. ту же страницу вики мой код тоже грузит на ура, как и любую другую страничку, проблема появляется призагрузке картинки через сокет (site.ru/cat/img.png например), как исправить?
PM MAIL   Вверх
Qu1nt
Дата 18.11.2008, 18:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 602
Регистрация: 13.1.2007

Репутация: 2
Всего: 50



В справку по strlen. И не забудь воспользоваться результатом RecBuf smile 

Это сообщение отредактировал(а) Qu1nt - 18.11.2008, 18:52
PM MAIL   Вверх
Virtuals
Дата 18.11.2008, 20:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 476
Регистрация: 27.11.2006

Репутация: 2
Всего: 11



MaDCoD, ну как о стенку горохом... "практически " не значит нигде

Qu1nt, прав, если внимательней посмотреть в strlen, то будет видно, что в вашем случае он ищет #00 и считает что это конец!

вот примерчик с кучей граблев  smile MaDCoDизучай, 
Qu1nt тоже посмотри, там хорошо видно что copy может тоже пролет устроить
Код

program Project2;

{$APPTYPE CONSOLE}

uses
  SysUtils;
type TBuf=array[0..131070]of char;
var buf:tbuf;
    s:string;
    s2:string;
    s3:ShortString;
begin
  { TODO -oUser -cConsole Main : Insert code here }
  writeln;
s:='ABC'+#0+#0+'def';
writeln(s);

strpcopy(buf,s);
writeln(buf);
writeln(strlen(buf));
s2:=copy(buf,1,8);
writeln(s2);//облом

StrLCopy(buf, PChar(S), 8);
writeln(buf);
writeln(strlen(buf));
s2:=copy(buf,1,8);
writeln(s2); //опять облом

move(s[1],buf,8);
writeln(buf); //ага в буфер наконец то попали данные в отладчике видно, хоть и не выводит на экран что логично
writeln(strlen(buf)); // :)
s2:=copy(buf,1,8);
writeln(s2); //опять облом  :( если копнуть copy то там найдем опять дуратскую проверку на 0 символ

s3:='12345678'; // ну мне так наглядней хотя можно и setlength
move(buf,s3[1],8);
writeln(s3); //ага вот оно

readln;
end.



соответственно в вашем коде нужно
buf[buflen]:=#0 никчему это

inplen:=RecBuf(S,buf);

ms.Write(buf,strlen(buf));
ms.Write(buf,inplen);  smile 

{либо
page:=StrPas(buf);

Код

setlength(page,inplen)
move(buf,page[1],inplen)


Это сообщение отредактировал(а) Virtuals - 19.11.2008, 07:59
PM MAIL ICQ   Вверх
darkmamba
Дата 20.11.2008, 14:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 98
Регистрация: 16.10.2008

Репутация: 1
Всего: 1



народ подскажите куда копать может подскажите готовое уже решение, начал недавно совсем изучать делфи и пишу щас програмку что то типо бота, вообщем соединяюсь с сервером, мне приходит пакет приветствия, на него я должен ответить правильным пакетом(ну это все проза), проблема щас для меня - какой тип переменных использовать под буфер принятых данных? стринг неподходит потомучто после нулевых символов строка обрезается, хотя когда писал чекер серверов на udp мне это немешало парсить пакеты, а с TCP все встало боком... нужно для отладки выводить принятый пакет, или хотябы быть уверенным что входящий пакет целиком принят, чтоб дальше работать с ним.. использовать тип стринг неподходит а с другими я работать неумею ^^, имхо идеальный вариант array of byte но как мне его вывести в любом виде (hex или ASCII или символы, главное чтоб полностью) в тот же мемо например, и как работать с этим типом, может литературу какуюнибуть подскажете или какихнибуть исходников подкинете, желательно VCL т.к я только учусь... опыта практически нет...использую компонент Tsocketclient. 

Это сообщение отредактировал(а) darkmamba - 20.11.2008, 14:56
PM MAIL   Вверх
Virtuals
Дата 20.11.2008, 20:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 476
Регистрация: 27.11.2006

Репутация: 2
Всего: 11




char:=ord(byte) символ по коду
string:=inttohex(byte,2) код в виде хекс размером 2 символа
darkmamba, 
PM MAIL ICQ   Вверх
darkmamba
Дата 22.11.2008, 18:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 98
Регистрация: 16.10.2008

Репутация: 1
Всего: 1



Virtuals, спасибо пригодилось!

щас решил проблему с обрезанием пакета делал так

Код

var
    Buffer : array [0..4096] of char;
    Len : Integer;
    pkt :string;
..
..

Len:=sock.Receive(@Buffer, SizeOf(Buffer));
  if Len >= 0 then begin
    pkt:='';
      for i:=0 to Len-1 do begin
          pkt:=pkt+Buffer[i];
      end;


но мне кажется это гимор для кода, и он будет тормазить при приеме больших пакетов и если их будет много...
PM MAIL   Вверх
Virtuals
Дата 22.11.2008, 20:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 476
Регистрация: 27.11.2006

Репутация: 2
Всего: 11



darkmamba, тебе правильно кажется, неоптимально!
посмотри в сторону move
прочти тему очень внимательно сначала!

и уйди от 
pkt :string;
иначе нарвешся на
pkt:='a'+#0+'3';
length(pkt) =1


Это сообщение отредактировал(а) Virtuals - 22.11.2008, 20:46
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Сети"
Snowy
Poseidon
MetalFan

Запрещено:

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делится вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи

Если Вам помогли и атмосфера форума Вам понравилась, то заходите к нам чаще! С уважением, Snowy, Poseidon, MetalFan.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.1251 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.