Вот кусок кода на MASM Суть в том, чтобы получить в буфер весь HTML код страницы. Размер буфера выделен с лихвой, но загрузка происходит всегда не полностью - размер выходного файла каждый раз разный и всегда кратен MTU. В чем может быть загвоздка? Код (Text): .486 .model flat, stdcall option casemap :none include \masm32\include\windows.inc include \masm32\include\kernel32.inc include \masm32\include\user32.inc include \masm32\include\ws2_32.inc includelib \masm32\lib\kernel32.lib includelib \masm32\lib\user32.lib includelib \masm32\lib\ws2_32.lib include \masm32\include\masm32.inc includelib \masm32\lib\masm32.lib .data szHostName db "www.wasm.ru",0 FileszHeaders db "POST /index.php HTTP/1.1",13,10 db "Host: www.wasm.ru",13,10 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 db "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",13,10 db "Accept-Language: en-us,en;q=0.7,de-de;q=0.3",13,10 db "Accept-Charset: windows-1250,utf-8;q=0.7,*;q=0.7",13,10 db "Keep-Alive: 115",13,10 db "Connection: keep-alive",13,10 db "Cookie:%s",13,10 db "Content-Type: application/x-www-form-urlencoded",13,10 db "Referer: http://www.wasm.ru/forum",13,10 db "Content-Length: 16",13,10,13,10 db "form_sent=1",0 outputFileName db 'file.htm', 0 .data? hFile dd ? writed dd ? url_file_string db 512 dup (?) f_startpos dd ? f_endpos dd ? f_lenstr dd ? startpos dd ? endpos dd ? lenstr dd ? podstroka3 db 255 dup (?) Ans_Buff db 100000 dup (?) Ans_Buff2 db 100000 dup (?) ;Ans_Buff2 dd ? Req_Buff db 1048 dup (?) Req_Buff2 db 1048 dup (?) cookies_str db 7500 dup (?) mHandle dd ? sizetoread dd ? .code ;======================================================================== filelink_Get_con proc LOCAL WSAData : WSADATA LOCAL saServer : sockaddr_in LOCAL pSocket : DWORD LOCAL dwLen : DWORD ; Init WSA invoke WSAStartup, 101h, addr WSAData test eax, eax jnz die ; Convert if IP invoke inet_addr, addr szHostName cmp eax, INADDR_NONE jne ok ; Resolve if host invoke gethostbyname, addr szHostName test eax, eax jz die mov eax, [eax+0Ch] mov eax, [eax] mov eax, [eax] ok: ; Fill struct mov saServer.sin_addr, eax invoke htons, 80d mov saServer.sin_port, ax mov saServer.sin_family, AF_INET ; Создаем socket invoke socket, AF_INET, SOCK_STREAM, 0 test eax, eax js die mov pSocket, eax ; Пробуем подсоедениться invoke connect, pSocket, addr saServer, sizeof saServer test eax, eax jnz die ; Создаем запрос серверу invoke wsprintf, addr Req_Buff2, addr FileszHeaders, addr cookies_str ; отправляем запрос invoke send, pSocket, addr Req_Buff2, eax, 0 test eax, eax js die jz die ; получаем ответ invoke recv, pSocket, addr Ans_Buff2, sizeof Ans_Buff2, 0 test eax, eax js die jz die push eax invoke closesocket, pSocket invoke WSACleanup ret die: invoke WSACleanup invoke ExitProcess, 0 filelink_Get_con endp ;======================================================================== ;======================================================================== Main proc call filelink_Get_con invoke CreateFile, addr outputFileName, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0 mov hFile,eax invoke lstrlen, addr Ans_Buff2 invoke WriteFile, hFile, addr Ans_Buff2, eax, addr writed, 0 invoke CloseHandle, hFile invoke MessageBox,0, addr Ans_Buff2, 0, MB_OK invoke ExitProcess, 0 Main endp end Main
Tverskoy Что-то примерно такое попробуй. Код (Text): RECV_SIZE equ 4096 ; большей буфер для считывания письма COUNT_LOOPrecv equ 700 ; колич чтений recv() большего письма ... xor ebx,ebx mov ebx,COUNT_LOOPrecv ; Мне не нужно ПОКА читать длинные письма .while ebx != 0 push ecx invoke GlobalAlloc,0,RECV_SIZE mov hMemRecv,eax invoke RtlZeroMemory, hMemRecv, RECV_SIZE pop ecx invoke recv, sock,hMemRecv,RECV_SIZE,0; принемаем из сокета 4096 байт (размер сам учтешь, ; чтобы не было переполнения) .if eax == 0 || eax == -1 || eax < RECV_SIZE; результат - количество принятых байт или ошибка .break ; если принято < чем RECV_SIZE значит это последняя .endif ; посылка из массива. Хотя может случиться так то ; хвост прямо ляжет в RECV_SIZEb ; ну тогда выйдет по eax==0 ; ну а дальше делаешь с полученой инфой все что ; тебе нужно dec ebx .endw
у меня пару раз до 500 писем из ящика считало, больше просто не пробовал. Но готов поучиться, мож че получше есть. )))
размер тела запросов/ответов в http однозначно определяется (это в RFC) по заголовку и телу added: то что это работает не значит что правильно, да и разговор об http, причем тут ваши письма, возможно это уже разрушительное влияние GPE
Да ну это конечно ты прав. В pop3, например, по LIST можно узнать размер письма. Ну а если не определить никак размер принимаемых данных заранее?
_sheva740 Ноль возвращается при разрыве соединения. А если данных ещё нет, то recv ждёт до посинения. Можно использовать select, неблокирующие сокеты, потоки и т.д.
Да, конечно, так ... лучше. Код (Text): .while ebx != 0 push ecx invoke GlobalAlloc,0,RECV_SIZE mov hMemRecv,eax invoke RtlZeroMemory, hMemRecv, RECV_SIZE pop ecx invoke select, 0, addr ???, addr ???, addr ???, addr time_out ; Ждем 500 ms .if eax==1 ; Если данные поступили invoke recv, sock,hMemRecv,RECV_SIZE,0; принемаем из сокета 1000h байт (размер сам учтешь, ; чтобы не было переполнения) .if eax == 0 || eax == -1 || eax < RECV_SIZE; результат - количество принятых байт или ошибка .break ; если принято < чем RECV_SIZE значит это последняя .endif ; посылка из массива. Хотя может случиться так то ; хвост прямо ляжет в RECV_SIZEb ; ну тогда выйдет по eax==0 ; ну а дальше делаешь с полученой инфой все что ; тебе нужно .endif dec ebx .endw
полагаться на то что это была не задержка передачи и считать что в потоке tcp закончились данные явно бред
Ты передаешь http/1.1 А значит, однозначно - парсить Content-Length и вычитывать ровно столько байт. А лучше читать RFC Если бы было http/1.0, тогда можно было бы читать до закрытия. Но уж точно не 1 раз и не полагаясь на то, что recv вернула меньше, чем просили
Если я правильно понял самый приемлемый алгоритм такой: - Получаем через Content-Length длину файла - Загоняем recv в цикл, попутно считывая сколько мы получили с него байт - Закрываем цикл как только значения совпали. (попутно отрабатывая Сокет-Еррор) Сразу возникает ряд вопросов вдогонку. 1) а что если сервер не передал значение Content-Length? Соответствено загружать файл пока не вскочит ошибка или буфер приема recv не выдаст значение 0... 2) И еще больше интересует вопрос о том как узнать есть уже в recv данные для приема или нет. Не Sleep'ом же пользоваться.
4.4 Message Length блокирующий не вернет управление до разрыва связи либо tcp timeout как уже указали выше: можно пользоваться select с таймаутом либо неблокирующими сокетами