Постил вопрос на RSDN'e, но без особого упеха, может тут найдется знающий человек? Пишу программу, в которой требуется получиь список фйлов на фтп сервере. InternetOpen и прочее не подходит, т.к FtpFindNext не умеет отличать файл от линка на файл. Пишу сейчас через команды, но столкнулся с проблемой. Делаю USER, PASS, CWD, PORT, LIST - всё нормально, приходит список файлов. Пытаюсь закрыть сокет, который получил после Accept - возвращает WSAEINVAL Настоящий же сокет(который на listen поставлен) закрывается нормально. Сервер, видимо, ждет закрытия сокета, потому что после команды LIST другие не выполняет. Посмотрел через снифер другой фтп клиент - после LIST идут пакеты серверу по FTP-DATA ACK, RST, у меня же их программа не посылает. Где может быть косяк? Код (Text): WndProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM mov eax,uMsg .if eax==WM_INITDIALOG push hWin pop hWnd and cmd_sock,0 and data_sock,0 .elseif eax==WM_COMMAND mov eax,wParam and eax,0FFFFh .if eax == go_btn invoke ftp_connect .endif .elseif eax==WM_CLOSE invoke DestroyWindow,hWin .elseif uMsg==WM_DESTROY invoke PostQuitMessage,NULL .else invoke DefWindowProc,hWin,uMsg,wParam,lParam ret .endif xor eax,eax ret WndProc endp create_listen_sock proc LOCAL sin: sockaddr_in LOCAL temp:DWORD invoke socket, AF_INET, SOCK_STREAM, IPPROTO_TCP mov data_sock,eax mov sin.sin_port,0 mov sin.sin_family,AF_INET mov sin.sin_addr,INADDR_ANY invoke bind, data_sock, addr sin , sizeof(sockaddr_in) invoke getsockname,data_sock,addr sin,addr temp;offset szSockaddr_in xor eax,eax mov ax,sin.sin_port invoke ntohs,eax invoke prep_port_cmd,eax ; тут готовится строка для PORT invoke listen, data_sock, 1 ret create_listen_sock endp ftp_connect proc uses ebx LOCAL sin: sockaddr_in LOCAL buff[255]:BYTE LOCAL buff2[255]:BYTE invoke SendDlgItemMessage,hWnd,serv_list,WM_GETTEXT,255,addr buff2 INVOKE inet_addr,addr buff2 .IF eax==INADDR_NONE INVOKE gethostbyname, addr buff2 .if eax == 0 jmp err .endif mov eax,dword ptr [eax+12] mov eax,dword ptr [eax] mov eax,dword ptr [eax] mov sin.sin_addr,eax .ELSE mov sin.sin_addr,eax .ENDIF mov sin.sin_port,1500h mov sin.sin_family,AF_INET mov sin.sin_addr,eax invoke lstrcpy, offset cur_path, offset cwd_cmd invoke socket, AF_INET, SOCK_STREAM, IPPROTO_TCP mov cmd_sock,eax ;invoke WSAAsyncSelect, cmd_sock, hWnd, WM_COMMANDSOCK,FD_READ+FD_CONNECT pd eax,"SELECT" invoke connect,cmd_sock,addr sin,sizeof(sockaddr_in) invoke recv,cmd_sock,cmd_buff,10000,0 invoke send_command,offset user_cmd invoke recv,cmd_sock,cmd_buff,10000,0 invoke send_command,offset pass_cmd invoke recv,cmd_sock,cmd_buff,10000,0 invoke send_command,offset cwd_cmd invoke recv,cmd_sock,cmd_buff,10000,0 invoke CreateListenSock invoke send_command,offset port_cmd invoke recv,cmd_sock,cmd_buff,10000,0 invoke send_command,offset list_cmd invoke recv,cmd_sock,cmd_buff,10000,0 invoke accept,data_sock,0,0;addr data_buff,1000;sizeof(sockaddr_in) mov real_data_sock,eax mov ebx,data_buff next_data: invoke recv,real_data_sock,ebx,50000,0 add ebx,eax test eax,eax jz next_data ;получаю список файлов sub ebx,data_buff mov ftp_data_size,ebx invoke closesocket,real_data_sock ; тут -1 invoke WSAGetLastError ; тут WSAENVAL(10022) invoke closesocket,data_sock ; этот нормально закрывается err: ret ftp_connect endp
>>Завершай сеанс командой QUIT перед закрытием сокета. Дык мне нужно не соединение с сервером закрыть, а канал данных. Он ждет пакета RST, после чего шлет мне по управляющему соединению что-нибудь вроде "200 Transfer Complete". Этот пакет видимо должен уходить после closesocket, но почему-то мастдай не даёт мне закрыть сокет. RFC'ы я читал, косяк не в командах, а в моей реализации под винду.
Блин, где ты раньше был? ( Уже всё переписал под пассивный режим, там без проблем. Но всё равно спасибо. Раз уж пошла такая пьянка,ещё такой вопрос. При коннекте (connect) на неотвечающий хост есть некий таймаут, после которого и синронный и асинхронный сокеты вываливаются с -1. Так вот, как можно изменить значение этого таймаута? Пробовал setsockopt(SO_RCVTIMEO) ошибки не возвращает, но и ничего не делает. Может это значение где-нить в реестре хранится? Можно, конечно, повесить это дело в отдельный тред и по собственному таймауту его убивать, но в MS так не советуют делать.
MSDN: BSD options not supported for setsockopt are: SO_RCVTIMEO int Receives time-out (available in Microsoft implementation of Windows Sockets 2). То есть для установки данной опции нужно в WSAStartup вторую версию запросить.