winsock косяк с принятием данных

Discussion in 'С/С++, C#, Rust, Swift, Go, Java, Perl, Ruby' started by InfectedM, 29 Aug 2009.

  1. InfectedM

    InfectedM Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    155
    Likes Received:
    12
    Reputations:
    0
    [delphi]winsock косяк с принятием данных

    хочу программно авторзироваться на форуме,но по неизвестной причине html страницка не принимаеться,принимаеться только заголовок и кусок начала страницы каторую я принимаю.почему?
    Code:
    unit Unit1;
    
    interface
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ExtCtrls, XPMan;
    
    const
      Host = 'forum.4game.ru';
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        Memo1: TMemo;
    
        procedure FormCreate(Sender: TObject);
        procedure FormDestroy(Sender: TObject);
        procedure Button1Click(Sender: TObject);
    
    
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      Form1: TForm1;
      Data : string;
    
    
    
    implementation
    uses
      WinSock;
    function IdSock(size:integer):string;
    var
      Sock    : TSocket;
      Addr    : TSockAddr;
      HostEnt : PHostEnt;
      Res     : Integer;
      Buf     : array [0..350001] of Char;
      Source  : string;
      I:integer;
    begin
    source:='';
    res:=0;
    
    Sock := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if Sock = INVALID_SOCKET then Exit; HostEnt := gethostbyname(PChar(Host));
    if HostEnt = nil then  Exit;Addr.sin_family := AF_INET;
    Addr.sin_port := htons(80);Addr.sin_addr   := PInAddr(HostEnt^.h_addr_list^)^;
    if connect(Sock, Addr, SizeOf(TSockAddr)) = SOCKET_ERROR then
    if WSAGetLastError() <> WSAEWOULDBLOCK then Exit;
    Res := send(Sock, Data[1], Length(Data), 0); if Res = SOCKET_ERROR then Exit;
    
      repeat
      if size=0 then Res := recv(Sock, Buf, SizeOf(Buf), 0)else
      Res := recv(Sock, Buf, size, 0);
      if Res = SOCKET_ERROR then Exit;
      if Res > 0 then Source := Source + Copy(Buf, 0, Res);
      until Res <= size;
    
    
    CloseSocket(Sock);
    result := Source;
    end;//IdSock
    
    function cook(a:integer;Co:string):string;//Co - ?????? ??? ???? ????
    var
    pos1:integer;
    str:string;
    i:integer;
    ckl:integer;
    begin
        for ckl:=1 to a do begin
         result:='';
         pos1:=pos('Set-Cookie:',co);
         co:=copy(co,pos1+12,length(co)-12);
         str:=co;
         I:=1;
        while str[i] <> ';' do begin
        result:=result+str[i];inc(i);
        end;
        end;
    end;
    
    {$R *.dfm}
    
    
    
    
    procedure TForm1.FormCreate(Sender: TObject);
    var
      WSAData : TWSAData;
    begin
      if WSAStartup($101, WSAData) <> 0 then
        Exit;
    end;
    
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
      WSACleanup;
    end;
    
    
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
    forum_4game_ruipb_stronghold:string;
       forum_4game_rusession_id:string;//????
       forum_4game_rumember_id:string;
       forum_4game_rupass_hash:string;
       forum_4game_rucoppa:    string;
       PHPSESSID:string;
       stat_uid:string;
    
       sid:string;
       pos1,pos2:integer;     //15-16 ???
        send:string;
    
        ckl,ckl2,st,I:integer;
        nick,pages,buf,str,attach_post_key,auth_key,Id:string;
        Otvet: TStringList;
    begin
    Otvet:= TStringList.Create;
    
    
    Data := 'GET /index.php?act=Login&CODE=00 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;
    form1.Memo1.text:=Idsock(50000);//Если поставить 0 ,то принимаеться нормально,но мне нужна не вся страничка
    memo1.Lines.SaveToFile('1.html');
    
    
    
    forum_4game_rusession_id:=cook(1,form1.Memo1.text);//forum_4game_rusession_id=4e9bec834c4da036ac55aeeb638591e7
    sid:=copy(forum_4game_rusession_id,26,32) ; // 4e9bec834c4da036ac55aeeb638591e7
    //showmessage(sid);
    
    
    
    send:='referer=&UserName=i11111&PassWord=42113340&CookieDate=1';
     Data := 'POST /index.php?s='+Sid+'&act=Login&CODE=01 HTTP/1.1'+#13#10+
    'Host: ' + Host + #13#10 +
    'User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.8.1.16) Gecko/20080702 Firefox/2.0.0.16'+#13#10+
    'Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5'+#13#10+
    'Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3'+#13#10+
    'Accept-Encoding: gzip,deflate'+#13#10+
    'Accept-Charset: windows-1251,utf-8;q=0.7,*;q=0.7'+#13#10+
    'Keep-Alive: 300'+#13#10+
    'Connection: keep-alive'+#13#10+
    'Referer: http://foru.4game.ru/index.php?act=Login&CODE=00'+#13#10+
    'Cookie: '+forum_4game_rusession_id+#13#10+
    'Content-Type: application/x-www-form-urlencoded'+#13#10+
    'Content-Length: '+inttostr(length(send))+#13#10#13#10+send;
    form1.Memo1.text:=Idsock(50000);  //входим //если поставить 0 принимаеться абракадабра минуты две
    memo1.Lines.SaveToFile('2.html');
    end;
    
    end.
    
    Idsock(50000) -> в скобках кол-во байт каторое хочу принять,если пушу 0 (чтоб принять все) то прога виснет на минуты 2,но в результате всеравно принимаю заголовок + иероглифы 23e8
    ‹Щ6?|trю±

    подскажите пожалуйста что можно сделать чтоб после post запроса страничка принималась полностью без иероглифов и зависаний на 5 минут


    http://depositfiles.com/files/5mu6im2xn
    http://ifolder.ru/13759577
    http://rapidshare.com/files/273009470/______IBP_2.3.5_USER_message.rar.html
    http://slil.ru/27937260
     
    #1 InfectedM, 29 Aug 2009
    Last edited: 29 Aug 2009
    1 person likes this.
  2. mr. ZetRikS

    mr. ZetRikS New Member

    Joined:
    17 Jul 2009
    Messages:
    45
    Likes Received:
    2
    Reputations:
    0
    Вот, сразу видно что человек хочет чб ему помогли... всё конкретно сказал что требуется и сорец приложил чб подправили...

    Оценил код... попробовал поюзать... у меня вообще аж папка с сорцом повисла О_о

    Теперь вроде раздуплилась...

    Чб всё не висло думаю нуна юзать поток отдельный, под запрос, а интерфейс пусть работает в 1ом (нулевом) потоке...

    И кстати, там в конце идёт сохранение файла из мемо в какой то рандомный хтмл файл... чего я почему то не узрел...

    Продолжаю изучать... мож ещё чего предложу...


    И так...

    По моему программа тормозит именно в function cook
    PHP:
    while str[i] <> ';' do
    begin 
         result
    :=result+str[i];inc(i);
    end;
    если вынесешь эту прцедуру в отдельный поток, то проблемы с подвисанием думаю больше не будет, нужно пробовать...


    и почему то не только в этой функции тормозит...
    Помоему она тормозит ещё и на этапе form1.Memo1.text:=Idsock(0);
    вызов которой уже в самом конце, до этого не так сильно...
    Да! именно тут и тормозит... почему то... в первый раз не тормозит... на втором вызове тормозит... вопрос почему? :)

    И кстати иероглифов я чё то вообще не заметил...

    Её тоже в поток пробовал выносить?
     
    #2 mr. ZetRikS, 29 Aug 2009
    Last edited: 29 Aug 2009
  3. InfectedM

    InfectedM Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    155
    Likes Received:
    12
    Reputations:
    0
    это я кое-что делал ,можно удалить:)

    в потоке так же принимаеться.
    для начало нужно понять почему принимаеться не вся страничка ,а ее часть к тому же криво/


    удалил ту процедуру с куками ,по прежнему виснет и принимаються иероглифы
    240c
    ‹€з@cuНњГ‰TП!ЬЮљщ(†ЛHрP3]LYпV/ТЇOгKуЄЏ©=ЖHsід‹шА¬oL^RС0ЗХA,Ъ·ѕ№э]*EБ‡НТ%№ПU“?О49[ШA‘OР“‘КQЩReU‰щxцd_ji–e¤Fэ4c_@ш[0М!h
     
    #3 InfectedM, 29 Aug 2009
    Last edited: 29 Aug 2009
  4. InfectedM

    InfectedM Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    155
    Likes Received:
    12
    Reputations:
    0
    угу...


    Data := 'GET /index.php?act=Login&CODE=00 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;
    form1.Memo1.text:=Idsock(0);

    работает норм,а второй раз не хочет
     
  5. mr. ZetRikS

    mr. ZetRikS New Member

    Joined:
    17 Jul 2009
    Messages:
    45
    Likes Received:
    2
    Reputations:
    0
    Нет, второй раз она работает, я пробовал через Ф7 прогу несколько раз... именно на втором вызове она задумывается...

    Может что то не так в запросе?
    так как первый запрос function IdSock обрабатывает корректно... на мой взгляд...


    О_о

    Счас попробовал после закрывания сокета его чистить... вообще как от неадекватно сработало... на первом как обычно чуть притормозила, но данные в мемо вывела... на втором походу вообше нифига делать не стала...

    И теперь понял почему...

    Странно... но интересно...

    Попробовал пересоздать сокет вообще...
    Всё равно тормозит... всё таки нужен отдельный поток под сокет и интерфейс...

    Вот результат ответа на второй запрос:

    HTML:
    HTTP/1.1 200 OK  Server: nginx/0.8.4  Date: Sat, 29 Aug 2009 15:22:36 GMT  Content-Type: text/html; charset=windows-1251  Transfer-Encoding: chunked  Connection: keep-alive  Keep-Alive: timeout=20  X-Powered-By: PHP/5.2.9-pl2-gentoo  Set-Cookie: forum_4game_rusession_id=cbead2e56584692848d652b74ea45ce7; path=/; domain=forum.4game.ru; httponly  Set-Cookie: PHPSESSID=3e405ae0d3dc688a8a7454610bf15ca7; path=/  Expires: Thu, 19 Nov 1981 08:52:00 GMT  Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0  Pragma: no-cache  Set-Cookie: forum_4game_ruipb_stronghold=7103949e45c7bb244f91c82d8fd9f2e3; expires=Sun, 29-Aug-2010 16:10:21 GMT; path=/; domain=forum.4game.ru; httponly  Set-Cookie: forum_4game_rumember_id=610758; expires=Sun, 29-Aug-2010 16:10:21 GMT; path=/; domain=forum.4game.ru; httponly  Set-Cookie: forum_4game_rupass_hash=d781feefcc1810bfe9a299e1b8158f25; expires=Sat, 05-Sep-2009 16:10:21 GMT; path=/; domain=forum.4game.ru; httponly  Set-Cookie: forum_4game_rucoppa=0; path=/; domain=forum.4game.ru  Set-Cookie: forum_4game_rusession_id=139cab4929d6588290a3499a88d31099; path=/; domain=forum.4game.ru; httponly  Set-Cookie: stat_uid=X4H4WkqZR7yzmzfVB29pAg==; path=/  Content-Encoding: gzip    23e8  ‹
     
    #5 mr. ZetRikS, 29 Aug 2009
    Last edited: 29 Aug 2009
  6. InfectedM

    InfectedM Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    155
    Likes Received:
    12
    Reputations:
    0
    ну от некоретности запроса она не должна виснуть поидее должна вернуть результат что данные не те .
    целый день марочаюсь не могу понять что не так,просто с инди перешол много не догоняю покачто :)
    эх,попробую еще раз с нуля написать мож косяки исчезнут сами собой)


    ps кто поможет разобраться с этой хренью чтобы работала быстро и не висла отблагодарю финансово :)
     
  7. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    'Accept-Encoding: gzip,deflate'+#13#10+

    этим ты говориш серваку что поддерживаеш сжатие gzip вот он тебе и возвращет данные в gzip'e

    'Connection: keep-alive'+#13#10+

    ставь
    'Connection: close'+#13#10+
    чтобы мозги не компосировать серваку.
    А позвисает потому что ждет дальнейшего ответа от сервака на команде recv
    так что нужно анализировать размер пришедших данных
    к примеру Contend-Length анализировать и считывать тока нужное кол-во байт.
    Или ставить таймауты на recv через setsockopt
     
    #7 slesh, 29 Aug 2009
    Last edited: 29 Aug 2009
    1 person likes this.
  8. InfectedM

    InfectedM Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    155
    Likes Received:
    12
    Reputations:
    0
    заменил то что ты сказал все заработало при выполнении функции IdSock(0) ничего не виснет вроде

    тоесть при отправке post запроса добавляем строку
    'Content-Length: 20000'+#13#10+
    и он вернет 20к байт вместо 70000(сктолько весит страничка)




    а это как?)
     
    #8 InfectedM, 29 Aug 2009
    Last edited: 29 Aug 2009
  9. InfectedM

    InfectedM Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    155
    Likes Received:
    12
    Reputations:
    0
    после добавления
    'Content-Length: 20000'

    возвращает


    HTTP/1.1 400 Bad Request
    Server: nginx/0.8.4
    Date: Sat, 29 Aug 2009 16:12:16 GMT
    Content-Type: text/html; charset=utf-8
    Content-Length: 172
    Connection: close
    Set-Cookie: stat_uid=X4H4WkqZU2CyHzfRB88RAg==; path=/

    <html>
    <head><title>400 Bad Request</title></head>
    <body bgcolor="white">
    <center><h1>400 Bad Request</h1></center>
    <hr><center>nginx/0.8.4</center>
    </body>
    </html>
     
  10. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    При POST запросе
    Content-Length должно содержать размер данных которые ты посылаеш.
    При приеме страницы часто в Content-Length сервер задает кол-во байт которые он возвращает
     
  11. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Вот тебе сервак ответил
    Content-Length: 172 - значит что после служебного залоговка (который оканчивается <CRLF><CRLF>) идет 172 байта данных.

    Когда ты шлеш данные (POST запрос) то ты должен указать сколько данных шлеш. У тебя там правильно стояло
    'Content-Length: '+inttostr(length(send))+#13#10#13#10+send;
     
  12. InfectedM

    InfectedM Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    155
    Likes Received:
    12
    Reputations:
    0
    а как с помощью пост запроса указать сколько байт возвращать ?
    весь результат POST запроса(вся страничка) весит 60500 байт ,а мне нужно от нее только 20000.

    как вернуть определенное кол-во байт?
    Idsock(20000) - возвращает почему-то максимум 2048
     
    #12 InfectedM, 29 Aug 2009
    Last edited: 29 Aug 2009
  13. Ra$cal

    Ra$cal Elder - Старейшина

    Joined:
    16 Aug 2006
    Messages:
    670
    Likes Received:
    185
    Reputations:
    78
    читай в цикле. далеко не всегда возможно считать ответ за один вызов.
     
  14. InfectedM

    InfectedM Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    155
    Likes Received:
    12
    Reputations:
    0
    если бы я знал как это)
    Code:
     repeat
     
      Res := recv(Sock, Buf, size, 0);
      if Res = SOCKET_ERROR then Exit;
      if Res > 0 then Source := Source + Copy(Buf, 0, Res);
      until Res <= size;
    считалось 2048, как начать считывать с 2048 до 4096
    неужели только таким гемором по 2048 байт?
     
    #14 InfectedM, 29 Aug 2009
    Last edited: 29 Aug 2009
  15. slesh

    slesh Elder - Старейшина

    Joined:
    5 Mar 2007
    Messages:
    2,702
    Likes Received:
    1,224
    Reputations:
    455
    Я бы сказал, но промолчу, чтобы небыло обид ) Просто скажу что код кривой "чуть" т.е. нелогичный. Это будет правильнее
    Code:
     size := сколько нужно считать
     fsize:=0; // типа сколько уже считано
     repeat
       Res := recv(Sock, Buf, size, 0);
       if Res = SOCKET_ERROR then break; // именно break потому как нужно выйти из цикла а не завершить всю обработку
       if Res > 0 then 
       begin
        fsize := fsize + Res; // увеличим счетчик того сколько мы всего считали
        Source := Source + Copy(Buf, 0, Res);
       end else break; 
      until fsize >= size; // типа читать пока данных меньше чем нами указано.
    
     
  16. InfectedM

    InfectedM Elder - Старейшина

    Joined:
    4 Nov 2007
    Messages:
    155
    Likes Received:
    12
    Reputations:
    0
    завтра попробую щас уже на за компом где d,заранее огромное спасибо)