Не могу получить весь дамп файла через сокеты

Тема в разделе "WASM.NETWORKS", создана пользователем Tverskoy, 13 мар 2011.

  1. Tverskoy

    Tverskoy New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2010
    Сообщения:
    3
    Вот кусок кода на MASM
    Суть в том, чтобы получить в буфер весь HTML код страницы.
    Размер буфера выделен с лихвой, но загрузка происходит всегда не полностью - размер выходного файла каждый раз разный и всегда кратен MTU. В чем может быть загвоздка?

    Код (Text):
    1. .486
    2. .model flat, stdcall
    3. option casemap :none
    4.  
    5. include \masm32\include\windows.inc
    6. include \masm32\include\kernel32.inc
    7. include \masm32\include\user32.inc
    8. include \masm32\include\ws2_32.inc
    9.  
    10. includelib \masm32\lib\kernel32.lib
    11. includelib \masm32\lib\user32.lib
    12. includelib \masm32\lib\ws2_32.lib
    13.  
    14. include     \masm32\include\masm32.inc
    15. includelib  \masm32\lib\masm32.lib
    16.  
    17. .data
    18.  
    19. szHostName  db "www.wasm.ru",0
    20.  
    21.  
    22.  
    23. FileszHeaders   db "POST /index.php HTTP/1.1",13,10
    24.         db "Host: www.wasm.ru",13,10
    25.         db "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; ru; rv:1.9.2.3) Gecko/20100401 Firefox/3.6.3 (.NET CLR 3.5.30729)",13,10
    26.             db "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",13,10
    27.         db "Accept-Language: en-us,en;q=0.7,de-de;q=0.3",13,10
    28.         db "Accept-Charset: windows-1250,utf-8;q=0.7,*;q=0.7",13,10
    29.         db "Keep-Alive: 115",13,10
    30.         db "Connection: keep-alive",13,10
    31.         db "Cookie:%s",13,10
    32.             db "Content-Type: application/x-www-form-urlencoded",13,10
    33.         db "Referer: http://www.wasm.ru/forum",13,10
    34.         db "Content-Length: 16",13,10,13,10
    35.             db "form_sent=1",0
    36.  
    37. outputFileName  db 'file.htm', 0
    38.  
    39.  
    40. .data?
    41.  
    42. hFile       dd ?
    43. writed      dd ?
    44.  
    45.  
    46. url_file_string db 512 dup (?)
    47. f_startpos  dd ?
    48. f_endpos    dd ?
    49. f_lenstr    dd ?
    50. startpos    dd ?
    51. endpos      dd ?
    52. lenstr      dd ?
    53. podstroka3  db 255 dup (?)
    54. Ans_Buff    db 100000 dup (?)
    55. Ans_Buff2   db 100000 dup (?)
    56. ;Ans_Buff2  dd ?
    57. Req_Buff    db 1048 dup (?)
    58. Req_Buff2   db 1048 dup (?)
    59. cookies_str db 7500 dup (?)
    60. mHandle     dd ?
    61. sizetoread  dd ?
    62. .code
    63.  
    64.  
    65. ;========================================================================
    66. filelink_Get_con proc
    67.     LOCAL WSAData       : WSADATA
    68.     LOCAL saServer      : sockaddr_in
    69.     LOCAL pSocket       : DWORD
    70.     LOCAL dwLen         : DWORD
    71.  
    72.     ; Init WSA
    73.     invoke  WSAStartup, 101h, addr WSAData
    74.     test    eax, eax
    75.     jnz     die
    76.  
    77.     ; Convert if IP
    78.     invoke  inet_addr, addr szHostName
    79.     cmp     eax, INADDR_NONE
    80.     jne     ok
    81.  
    82.     ; Resolve if host
    83.     invoke  gethostbyname, addr szHostName
    84.     test    eax, eax
    85.     jz      die
    86.  
    87.     mov     eax, [eax+0Ch]
    88.     mov     eax, [eax]
    89.     mov     eax, [eax]
    90.  
    91.     ok:
    92.     ; Fill struct
    93.     mov     saServer.sin_addr, eax
    94.     invoke  htons, 80d
    95.     mov     saServer.sin_port, ax
    96.     mov     saServer.sin_family, AF_INET
    97.  
    98.     ; Создаем socket
    99.     invoke  socket, AF_INET, SOCK_STREAM, 0
    100.     test    eax, eax
    101.     js      die
    102.     mov     pSocket, eax
    103.  
    104.     ; Пробуем подсоедениться
    105.     invoke  connect, pSocket, addr saServer, sizeof saServer
    106.     test    eax, eax
    107.     jnz     die
    108.  
    109.     ; Создаем запрос серверу
    110.     invoke  wsprintf, addr Req_Buff2, addr FileszHeaders, addr cookies_str
    111.  
    112.     ; отправляем запрос
    113.     invoke  send, pSocket, addr Req_Buff2, eax, 0
    114.     test    eax, eax
    115.     js      die
    116.     jz      die
    117.  
    118.     ; получаем ответ
    119.  
    120.  
    121.     invoke  recv, pSocket, addr Ans_Buff2, sizeof Ans_Buff2, 0
    122.  
    123.     test    eax, eax
    124.     js      die
    125.     jz      die
    126.     push    eax
    127.     invoke  closesocket, pSocket
    128.     invoke  WSACleanup
    129. ret
    130. die:
    131. invoke  WSACleanup
    132. invoke  ExitProcess, 0
    133. filelink_Get_con endp
    134. ;========================================================================
    135.  
    136.  
    137. ;========================================================================
    138.  
    139. Main proc
    140.  
    141. call filelink_Get_con
    142.  
    143.     invoke  CreateFile, addr outputFileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0
    144.     mov hFile,eax
    145.     invoke  lstrlen, addr Ans_Buff2
    146.     invoke  WriteFile, hFile, addr Ans_Buff2, eax, addr writed, 0
    147.     invoke  CloseHandle, hFile
    148.  
    149. invoke  MessageBox,0, addr Ans_Buff2, 0, MB_OK
    150.  
    151. invoke  ExitProcess, 0
    152. Main endp
    153. end Main
     
  2. fsd

    fsd New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2010
    Сообщения:
    353
    почитайте плз как работает recv, тема явно в BEGINNERS
     
  3. _sheva740

    _sheva740 New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2005
    Сообщения:
    1.539
    Адрес:
    Poland
    Tverskoy
    Что-то примерно такое попробуй.
    Код (Text):
    1.     RECV_SIZE       equ 4096    ; большей буфер для считывания письма
    2.     COUNT_LOOPrecv  equ 700 ; колич чтений  recv() большего письма  
    3.  
    4. ...
    5.             xor ebx,ebx
    6.             mov ebx,COUNT_LOOPrecv  ; Мне не нужно ПОКА читать длинные письма 
    7.             .while ebx != 0
    8.                 push    ecx
    9.                 invoke  GlobalAlloc,0,RECV_SIZE
    10.                 mov hMemRecv,eax
    11.                 invoke  RtlZeroMemory, hMemRecv, RECV_SIZE
    12.                 pop ecx
    13.                     invoke recv, sock,hMemRecv,RECV_SIZE,0; принемаем из сокета 4096 байт (размер сам учтешь,
    14.                                     ; чтобы не было переполнения)
    15.                     .if eax == 0 || eax == -1 || eax < RECV_SIZE; результат - количество принятых байт или ошибка
    16.                         .break          ; если принято < чем RECV_SIZE значит это последняя
    17.                     .endif              ; посылка  из массива. Хотя может случиться так то
    18.                             ; хвост прямо ляжет в RECV_SIZEb
    19.                             ; ну тогда выйдет по eax==0
    20.                             ; ну а дальше делаешь с полученой инфой все что
    21.                             ; тебе нужно
    22.                 dec ebx
    23.             .endw
     
  4. fsd

    fsd New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2010
    Сообщения:
    353
    плохие советы
     
  5. _sheva740

    _sheva740 New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2005
    Сообщения:
    1.539
    Адрес:
    Poland
    у меня пару раз до 500 писем из ящика считало,
    больше просто не пробовал.
    Но готов поучиться, мож че получше есть. )))
     
  6. fsd

    fsd New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2010
    Сообщения:
    353
    размер тела запросов/ответов в http однозначно определяется (это в RFC) по заголовку и телу

    added:
    то что это работает не значит что правильно, да и разговор об http, причем тут ваши письма, возможно это уже разрушительное влияние GPE
     
  7. _sheva740

    _sheva740 New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2005
    Сообщения:
    1.539
    Адрес:
    Poland
    Да ну это конечно ты прав.
    В pop3, например, по LIST можно узнать размер письма.
    Ну а если не определить никак размер принимаемых данных заранее?
     
  8. Booster

    Booster New Member

    Публикаций:
    0
    Регистрация:
    26 ноя 2004
    Сообщения:
    4.860
    _sheva740
    Ноль возвращается при разрыве соединения. А если данных ещё нет, то recv ждёт до посинения. Можно использовать select, неблокирующие сокеты, потоки и т.д.
     
  9. _sheva740

    _sheva740 New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2005
    Сообщения:
    1.539
    Адрес:
    Poland
    Да, конечно, так ... лучше.
    Код (Text):
    1.             .while ebx != 0
    2.                 push    ecx
    3.                 invoke  GlobalAlloc,0,RECV_SIZE
    4.                 mov hMemRecv,eax
    5.                 invoke  RtlZeroMemory, hMemRecv, RECV_SIZE
    6.                 pop ecx
    7.                 invoke  select, 0,  addr ???, addr ???, addr ???, addr time_out ; Ждем 500 ms
    8.                 .if eax==1                  ; Если данные поступили
    9.                     invoke recv, sock,hMemRecv,RECV_SIZE,0; принемаем из сокета 1000h байт (размер сам учтешь,
    10.                                     ; чтобы не было переполнения)
    11.                     .if eax == 0 || eax == -1 || eax < RECV_SIZE; результат - количество принятых байт или ошибка
    12.                         .break          ; если принято < чем RECV_SIZE значит это последняя
    13.                     .endif              ; посылка  из массива. Хотя может случиться так то
    14.                             ; хвост прямо ляжет в RECV_SIZEb
    15.                             ; ну тогда выйдет по eax==0
    16.                             ; ну а дальше делаешь с полученой инфой все что
    17.                             ; тебе нужно
    18.                 .endif 
    19.                 dec ebx
    20.             .endw
     
  10. fsd

    fsd New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2010
    Сообщения:
    353
    полагаться на то что это была не задержка передачи и считать что в потоке tcp закончились данные явно бред
     
  11. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Ты передаешь http/1.1
    А значит, однозначно - парсить Content-Length и вычитывать ровно столько байт. А лучше читать RFC

    Если бы было http/1.0, тогда можно было бы читать до закрытия. Но уж точно не 1 раз и не полагаясь на то, что recv вернула меньше, чем просили
     
  12. Tverskoy

    Tverskoy New Member

    Публикаций:
    0
    Регистрация:
    16 дек 2010
    Сообщения:
    3
    Если я правильно понял самый приемлемый алгоритм такой:
    - Получаем через Content-Length длину файла
    - Загоняем recv в цикл, попутно считывая сколько мы получили с него байт
    - Закрываем цикл как только значения совпали. (попутно отрабатывая Сокет-Еррор)

    Сразу возникает ряд вопросов вдогонку.
    1) а что если сервер не передал значение Content-Length? Соответствено загружать файл пока не вскочит ошибка или буфер приема recv не выдаст значение 0...
    2) И еще больше интересует вопрос о том как узнать есть уже в recv данные для приема или нет. Не Sleep'ом же пользоваться.
     
  13. fsd

    fsd New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2010
    Сообщения:
    353
    4.4 Message Length
    блокирующий не вернет управление до разрыва связи либо tcp timeout
    как уже указали выше: можно пользоваться select с таймаутом либо неблокирующими сокетами