Как-то странно работает функция recv!!! Как правильно скачивать Web-странички? Код (Text): CrLf equ 0Dh,0Ah ;SITE equ "www.samara.ru" SITE equ "www.yandex.ru" url db SITE,0h BUFFER_SIZE equ 50000h DELAY equ 500h myconnect PROTO :DWORD,:DWORD DNS_ERROR equ 465h myconnect proc hWnd,hMemo LOCAL s:SOCKET LOCAL memheap:DWORD LOCAL procheap:DWORD LOCAL sin:SOCKADDR_IN LOCAL handle:DWORD LOCAL bytes:DWORD LOCAL membuffer:DWORD LOCAL result:DWORD LOCAL str_len:DWORD nop nop nop nop nop invoke GetProcessHeap mov procheap,eax ;invoke HeapAlloc,eax,HEAP_ZERO_MEMORY,BUFFER_SIZE invoke VirtualAlloc,0h,BUFFER_SIZE,MEM_COMMIT,PAGE_READWRITE mov memheap,eax invoke HeapAlloc,procheap,HEAP_ZERO_MEMORY,4000h mov membuffer,eax invoke WSAStartup,101h,offset wsadata invoke socket,AF_INET,SOCK_STREAM,0h mov s,eax mov eax,memheap invoke gethostbyname,offset url .if eax==0h mov result,DNS_ERROR .data dns_error db "DNS Error!!!",0h .code invoke SendMessage,hMemo,WM_SETTEXT,sizeof dns_error,offset dns_error jmp endy .endif assume eax:ptr HOSTENT mov eax,[eax].h_addr assume eax:nothing mov eax,[eax] mov eax,[eax] mov sin.sin_addr.s_addr,eax mov sin.sin_port,5000h mov sin.sin_family,AF_INET invoke connect,s,addr sin,sizeof(sockaddr_in) ;xor eax,eax .if eax==0h .data send_data db "GET / HTTP/1.1",CrLf db "Host: ",SITE,CrLf db "Accept: */*",CrLf db "Accept-Language: ru",CrLf db "Accept-Encoding: deflate",CrLf db "User-Agent: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 8.1; SV1; .NET CLR 2.4.98777)",CrLf db "Connection: keep-alive",CrLf,CrLf db 0h .code invoke lstrlen,offset send_data invoke send,s,offset send_data,eax,0h ;invoke Sleep,DELAY invoke recv,s,memheap,BUFFER_SIZE,0h mov str_len,eax invoke CreateFile,$CTA0("log.txt"),GENERIC_READ or GENERIC_WRITE,0h,0h,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0h mov handle,eax invoke WriteFile,handle,memheap,BUFFER_SIZE,addr bytes,0h invoke CloseHandle,handle ;invoke closesocket,s invoke WSACleanup ;invoke lstrlen,memheap mov eax,str_len invoke SendMessage,hMemo,WM_SETTEXT,eax,memheap nop nop nop nop nop mov eax,str_len nop nop nop nop nop .endif invoke HeapFree,procheap,0h,membuffer ;invoke HeapFree,procheap,0h,memheap invoke VirtualFree,memheap,BUFFER_SIZE,MEM_DECOMMIT endy: mov eax,result ret myconnect endp Вот непонятное место: Код (Text): invoke lstrlen,offset send_data invoke send,s,offset send_data,eax,0h ;invoke Sleep,DELAY invoke recv,s,memheap,BUFFER_SIZE,0h mov str_len,eax Почему-то если invoke Sleep,DELAY в коментариях, то скачивается неполностью www.samara.ru, а www.yandex.ru скачивается полностью, а если invoke Sleep,DELAY, то скачивается полностью www.samara.ru, а www.yandex.ru скачивается неполностью!!! Причём каждый раз неполноскачанная страничка обрывается на одном и том же месте! Что за ерунда?
Meatcoins Что за ерунда? imho, прежде чем писать программу, необходимо ознакомиться с теорией. Начать можно с Самоучитель игры на WINSOCK.
наверное ты не всю страницу принимаешь просто С чего ты решил что за один recv ты получишь всю страницу? Второй recv сделать не пробовал
Спасибо за ссылочку http://www.citforum.ru/ Есть там кое-что почитать.... Несколько раз recv я пробывал вызывать - работает - считывается по частям всё! Например, длинные сайты, типа www.samara.ru считываются по частям при помощи вызова recv несколько ряд подряд. Но если вызывать recv в цикле, то на какой-то итерации, когда не будет данных, прога просто зависнет - будет ждать данных от узла, а они уже кончились! Мне что поток создавать, делать TIMEOUT, а потом мочить его по TIMEOUT'у??? Что-то сложновато как-то... хотелось бы конечно за 1 recv - буфер-то я могу выделить хоть 100Mбайт! Что ему мешает? Хотя тут цикл какой-то: while((nsize=recv(my_sock,&buff[0], sizeof(buff)-1,0)) !=SOCKET_ERROR) Попробую так... Блин, смотрю на код и думаю... Разьве recv возвращает SOCKET_ERROR, помоему она просто зависает и ждёт данные, и всё!
Можно привязать FD_READ к обработчику сообщений окна через WSAAsyncSelect или использовать WSAEventSelect. Читайте MSDN по этим функциям. А самоучитель игры на WINSOCK - детский сад. ИМХО.
Meatcoins Когда данные закончились recv возвращает 0. А если после этого опять вызвать recv, то она будет бесконечно ждать.
GastiX Что-то ты вообще нихуа не в тему сказал. Причем здесь эвенты и события? От того, что ты переключишь сокет в неблокирующий режим, смысл программы не поменяется.
Какая интресная шляпа! Хочется разобраться. Когда страница полностью закачена, сервер должен завершить соеденение, при этом recv должен вернуть NULL. SOCKET_ERROR recv возвращает только тогда, когда соеденение оборвано (закрыто некорректно).
Meatcoins Кстати, я не знаю по какой причине, при резервировании с помощью VirtualAlloc большого объема для буфера приема-отправки, у меня тоже возникали проблемы с недогрузом страниц. Копать не стал тогда эту проблему, просто взял 800h из стека и закрутил в цикле. Все стало работать. Попробуй. Судя по описанию, эта книга очень похожа на переделанную под Винду "UNIX. Разработка сетевых приложений". Очень даже не плохая книга, рекомендую (самоучитель не читал). Порекомендуй не детский сад, тогда уж... раз такой взрослый.
Всем спасибо! Всё работает! Действительно, ничего сложного... А за ссылочки спасибо! Код (Text): CrLf equ 0Dh,0Ah ;SITE equ "www.samara.ru" SITE equ "www.yandex.ru" url db SITE,0h BUFFER_SIZE equ 50000h RECV_SIZE equ 100h DELAY equ 500h myconnect PROTO :DWORD,:DWORD DNS_ERROR equ 465h myconnect proc hWnd,hMemo LOCAL s:SOCKET LOCAL memheap:DWORD LOCAL procheap:DWORD LOCAL sin:SOCKADDR_IN LOCAL handle:DWORD LOCAL bytes:DWORD LOCAL membuffer:DWORD LOCAL result:DWORD LOCAL str_len:DWORD invoke GetProcessHeap mov procheap,eax invoke VirtualAlloc,0h,BUFFER_SIZE,MEM_COMMIT,PAGE_READWRITE mov memheap,eax invoke HeapAlloc,procheap,HEAP_ZERO_MEMORY,4000h mov membuffer,eax invoke WSAStartup,101h,offset wsadata invoke socket,AF_INET,SOCK_STREAM,0h mov s,eax mov eax,memheap invoke gethostbyname,offset url .if eax==0h mov result,DNS_ERROR .data dns_error db "DNS Error!!!",0h .code invoke SendMessage,hMemo,WM_SETTEXT,sizeof dns_error,offset dns_error jmp endy .endif assume eax:ptr HOSTENT mov eax,[eax].h_addr assume eax:nothing mov eax,[eax] mov eax,[eax] mov sin.sin_addr.s_addr,eax mov sin.sin_port,5000h mov sin.sin_family,AF_INET invoke connect,s,addr sin,sizeof(sockaddr_in) ;xor eax,eax .if eax==0h .data send_data db "GET / HTTP/1.1",CrLf db "Host: ",SITE,CrLf db "Accept: */*",CrLf db "Accept-Language: ru",CrLf db "Accept-Encoding: deflate",CrLf db "User-Agent: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 8.1; SV1; .NET CLR 2.4.98777)",CrLf db "Connection: keep-alive",CrLf,CrLf db 0h .code invoke lstrlen,offset send_data invoke send,s,offset send_data,eax,0h mov edx,memheap mov eax,1h .while eax!=0h push edx invoke recv,s,edx,RECV_SIZE,0h pop edx add edx,eax .endw sub edx,memheap mov str_len,edx invoke CreateFile,$CTA0("log.txt"),GENERIC_READ or GENERIC_WRITE,0h,0h,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL,0h mov handle,eax invoke WriteFile,handle,memheap,str_len,addr bytes,0h invoke CloseHandle,handle invoke closesocket,s invoke WSACleanup mov eax,str_len invoke SendMessage,hMemo,WM_SETTEXT,eax,memheap .endif invoke HeapFree,procheap,0h,membuffer invoke VirtualFree,memheap,BUFFER_SIZE,MEM_DECOMMIT endy: mov eax,result ret myconnect endp
Вроде всё сделал правильно, но yahoo.ru (68.180.206.184) не качается. Зато если в "Host:" написать 127.0.0.1 и запустить сервер, то страница грузится. Может кто обьяснить что не так, кому не сложно? Код (Text): .data GetTemplate db "GET / HTTP/1.1",13,10 db "Host: 68.180.206.184",13,10 db "Accept: */*",13,10,13,10,0 HostName db "68.180.206.184",0 hSock1 dd 0 .data? wsadata WSADATA <> SA sockaddr_in <> BufferHTML db 1024 dup(?) .const WM_SOCKET equ WM_USER+257 ... ... .ELSEIF uMsg==WM_SHOWWINDOW invoke socket,PF_INET,SOCK_STREAM,0 mov hSock1,eax invoke inet_addr,addr HostName .if eax==INADDR_NONE invoke gethostbyname,addr HostName mov eax,[eax+12] mov eax,[eax] mov eax,[eax] mov SA.sin_addr,eax .else mov SA.sin_addr,eax .endif mov SA.sin_family,AF_INET invoke htons,80 mov SA.sin_port,ax invoke WSAAsyncSelect,hSock1,hWnd,WM_SOCKET,FD_CONNECT or FD_READ or FD_CLOSE invoke connect,hSock1,addr SA,sizeof SA .ELSEIF uMsg==WM_SOCKET .IF ax==FD_CONNECT invoke send,hSock1,addr GetTemplate,eax,0 .ELSEIF ax==FD_READ invoke recv,hSock1,offset BufferHTML,1024,0 .ELSEIF ax==FD_CLOSE INVOKE closesocket,hSock1
Привет! Вообще поле Host в протоколе HTTP используется, чтобы дать понять серверу, который находится на определённом IP, какой из виртуальных host'ов ты хочешь грузить - там должно быть www.yahoo.ru, а не IP! Попробуй ещё указать: db "Accept-Encoding: deflate",CrLf - чтобы то, что ты скачаешь было не закодировано и не сжато by gzip! db "Connection: keep-alive",CrLf,CrLf - "хранить" соединение!
Спасибо. Но invoke connect по прежнему упорно возвращает "-1". Уже всё испробовал - безрезультатно. Видимо после ".ELSEIF uMsg==WM_SHOWWINDOW" есть какая то ошибка! Вот полный исходник http://wasm.ru/forum/attachment.php?item=2571 Код (Text): .386 .model flat,stdcall option casemap:none WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD include c:\temp\masm32\include\windows.inc include c:\temp\masm32\include\user32.inc includelib c:\temp\masm32\lib\user32.lib include c:\temp\masm32\include\kernel32.inc includelib c:\temp\masm32\lib\kernel32.lib include c:\temp\masm32\include\shell32.inc includelib c:\temp\masm32\lib\shell32.lib include c:\temp\masm32\include\wsock32.inc includelib c:\temp\masm32\lib\wsock32.lib include c:\temp\masm32\include\advapi32.inc includelib c:\temp\masm32\lib\advapi32.lib .data ClassName db "DLGCLASS",0 DlgName db "Form1",0 ;;;addresIP db "68.180.206.184",0 HostName db "68.180.206.184",0 GetTemplate db "GET / HTTP/1.1",13,10 db "Host: www.yahoo.ru",13,10 db "Accept-Encoding: deflate",13,10 db "Connection: keep-alive",13,10 db "Accept: */*",13,10,13,10,0 hFile dd 0 hSock1 dd 0 hReg dd 0 pType dd 0 .data? hInstance HINSTANCE ? CommandLine LPSTR ? hDlg dd ? wsadata WSADATA <> SA sockaddr_in <> BufferHTML db 1024 dup(?) .const WM_SOCKET equ WM_USER+257 .code program: INVOKE GetModuleHandle,0 mov hInstance,eax INVOKE GetCommandLine mov CommandLine,eax INVOKE WinMain,hInstance,0,CommandLine,SW_SHOWDEFAULT INVOKE ExitProcess,eax WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD LOCAL wc:WNDCLASSEX LOCAL msg:MSG mov wc.cbSize,SIZEOF WNDCLASSEX mov wc.style,CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc,OFFSET WndProc mov wc.cbClsExtra,0 mov wc.cbWndExtra,DLGWINDOWEXTRA push hInst pop wc.hInstance mov wc.hbrBackground,COLOR_BTNFACE+1 mov wc.lpszClassName,OFFSET ClassName mov wc.lpszMenuName,0 INVOKE LoadIcon,hInstance,0 mov wc.hIcon,eax mov wc.hIconSm,eax INVOKE LoadCursor,0,IDC_ARROW mov wc.hCursor,eax INVOKE WSAStartup,101h,offset wsadata INVOKE RegisterClassEx,addr wc INVOKE CreateDialogParam,hInstance,offset DlgName,0,0,0 mov hDlg,eax INVOKE ShowWindow,hDlg,SW_SHOWNORMAL INVOKE UpdateWindow,hDlg .WHILE TRUE INVOKE GetMessage,addr msg,0,0,0 .BREAK .IF (!eax) INVOKE TranslateMessage,addr msg INVOKE DispatchMessage,addr msg .ENDW INVOKE WSACleanup mov eax,msg.wParam ret WinMain endp WndProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM .IF uMsg==WM_DESTROY invoke closesocket,hSock1 invoke PostQuitMessage,0 .ELSEIF uMsg==WM_SHOWWINDOW invoke socket,PF_INET,SOCK_STREAM,0 mov hSock1,eax invoke inet_addr,addr HostName .if eax==INADDR_NONE invoke gethostbyname,addr HostName mov eax,[eax+12] mov eax,[eax] mov eax,[eax] mov SA.sin_addr,eax .else mov SA.sin_addr,eax .endif mov SA.sin_family,AF_INET invoke htons,80 mov SA.sin_port,ax invoke WSAAsyncSelect,hSock1,hWnd,WM_SOCKET,FD_CONNECT or FD_READ or FD_CLOSE invoke connect,hSock1,addr SA,sizeof SA .ELSEIF uMsg==WM_COMMAND mov eax,wParam .IF ax==1003 invoke closesocket,hSock1 invoke ExitProcess,0 .ENDIF .ELSEIF uMsg==WM_SOCKET mov eax,lParam and eax,0FFFFh .IF ax==FD_CONNECT invoke send,hSock1,addr GetTemplate,eax,0 invoke recv,hSock1,offset BufferHTML,1024,0 .ELSEIF ax==FD_READ invoke recv,hSock1,offset BufferHTML,1024,0 .ENDIF .ELSEIF ax==FD_CLOSE invoke closesocket,hSock1 .ENDIF INVOKE DefWindowProc,hWnd,uMsg,wParam,lParam ret xor eax,eax ret WndProc endp end program
trr Ты переводишь сокет в асинхронный режим вызовом WSAAsyncSelect. Соеденение происходит, просто connect возвращает управление раньше,поэтому и -1. Если убрать WSAAsyncSelect, то в блокирующем режиме он будет ждать установления соеденения и будет возвращать 0. Сообщение о коннекте тоже приходит, кстати.
Теперь разобрался. Думал -1 это не нормально. Вот что пришло от yahoo.ru: Код (Text): HTTP/1.1 301 Moved Permanently Date=Fri, 17 Oct 2008 09:59:05 GMT Location=http://ru.yahoo.com/ Connection=close Transfer-Encoding=chunked Content-Type=text/html; charset=utf-8 Чуствую, так и не скачаю я эту страницу
trr Ты ее пробавал в браузере набирать? Сравни то, что появляется в строке браузера при наборе yahoo.ru, и что за страница вылезает, когда ввести туда тот адрес по которому ты пытаешься законнектиться.