
Шустрый

Профиль
Группа: Участник
Сообщений: 54
Регистрация: 22.8.2007
Где: г. Тольятти
Репутация: 2 Всего: 5
|
Здраствуйте. Необходимо скачать текстовый файл с сервера через сокеты. Раньше использовал WinInet функции. Соединялся, проверял ответ от сервера и заполнял буфер данными, которые потом использовал по назначению. Код был такой: | Код | function GetTextFileFromServer(szURL : AnsiString) : AnsiString; var FSession : HINTERNET; hConnect : HINTERNET; szBuffer : Array [0..4095] of AnsiChar; dwIndex : DWORD; dwCodeLen : DWORD; hRequest : LongBool; szNotify : AnsiString; dwTimeout : Integer; dwRead : Cardinal; begin Result := ''; try { открываем интернет сессию для выполнения последующих действий } FSession := InternetOpen('Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)', INTERNET_OPEN_TYPE_PRECONFIG, nil, nil, 0); { устанавливаем таймер на сессию - 10 секунд } dwTimeout := 10 * 1000; InternetSetOption(FSession, INTERNET_OPTION_CONNECT_TIMEOUT, @dwTimeout, SizeOf(dwTimeout)); InternetSetOption(FSession, INTERNET_OPTION_RECEIVE_TIMEOUT, @dwTimeout, SizeOf(dwTimeout)); InternetSetOption(FSession, INTERNET_OPTION_SEND_TIMEOUT, @dwTimeout, SizeOf(dwTimeout)); if FSession <> nil then try { получаем хэндл открытого файла по сети } hConnect := InternetOpenUrl(FSession, PAnsiChar(szURL), nil, 0, INTERNET_FLAG_NO_UI, 0); if hConnect <> nil then try { проверяем открытое соединение на ошибки } dwIndex := 0; dwCodeLen := Length(szBuffer); hRequest := HttpQueryInfo(hConnect, HTTP_QUERY_STATUS_CODE, @szBuffer[0], dwCodeLen, dwIndex); if hRequest then begin szNotify := szBuffer; { если код ошибки 200 - все прошло нормально и продолжаем } if szNotify = '200' then begin repeat FillChar(szBuffer, SizeOf(szBuffer), 0); if InternetReadFile(hConnect, @szBuffer[0], SizeOf(szBuffer), dwRead) then Result := Result + szBuffer else Break; until dwRead = 0; end; end; finally InternetCloseHandle(hConnect); end; finally InternetCloseHandle(FSession); end; except end; end;
|
Собственно до поры дов ремени мне было этого достаточно. Но недостаток этого кода в том фиг знает, но если что-то пошло не так с первого раза после запуска приложения - файл не качается - хоть до посинения вызывай эту функцию... Решил скачивать файл через сокеты. Посмотрел что люди пишут и решил написать код: | Код | function GetHttpData(szURL, szMethod : AnsiString; dwPort : WORD; szArgs, szContent : AnsiString) : AnsiString; var hSocket : TSocket; SockAddr : TSockAddr; szBuffer : Array [0..1023] of AnsiChar; BuffSize : Cardinal; WSAData : TWSAData; szTemp : AnsiString; szHost : AnsiString; sHostEnt : PHostEnt; sTimeout : Integer; begin { возвращаем пустой результат в функцию } Result := ''; { извлекаем название хоста для соединения } szTemp := szURL; if Pos('//', szTemp) > 0 then Delete(szTemp, 1, Pos('//', szTemp) + 1); szHost := Copy(szTemp, 1, Pos('/', szTemp) - 1); { запускаем библиотеку winsock версии 2 } if WSAStartup(MAKEWORD(2, 0), WSAData) <> NOERROR then Exit; { пытаемся извлечь название хоста } sHostEnt := GetHostByName(PAnsiChar(szHost)); if sHostEnt = nil then begin WSACleanup; Exit; end; { создаем сокет с нужными нам параметрами } hSocket := socket(PF_INET, SOCK_STREAM, IPPROTO_IP); if hSocket = INVALID_SOCKET then begin WSACleanup; Exit; end; FillChar(SockAddr, SizeOf(sockaddr_in), 0); SockAddr.sin_family := AF_INET; SockAddr.sin_addr := PInAddr(sHostEnt^.h_addr_list^)^; SockAddr.sin_port := htons(dwPort); { устанавливаем интервалы таймаута } sTimeout := 1000000; setsockopt(hSocket, SOL_SOCKET, SO_RCVTIMEO, @sTimeout, SizeOf(Integer)); setsockopt(hSocket, SOL_SOCKET, SO_SNDTIMEO, @sTimeout, SizeOf(Integer)); { если не удалось соединиться - останавливаемся } if connect(hSocket, SockAddr, SizeOf(SockAddr)) = SOCKET_ERROR then begin shutdown(hSocket, SD_BOTH); closesocket(hSocket); WSACleanup; Exit; end; { формируем строку для отправки запроса } szTemp := Format('%s %s HTTP/1.1' + sLineBreak + '%s' + sLineBreak + 'User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)' + sLineBreak + 'Host: %s' + sLineBreak + 'Content-Length: %s' + sLineBreak + 'Connection: Keep-Alive' + sLineBreak + 'Cache-Control: no-cache' + sLineBreak + sLineBreak + szArgs, [szMethod, szURL, szContent, szHost, IntToStr(Length(szArgs))]); { отправляем через сокет запрос } if send(hSocket, Pointer(szTemp)^, Length(szTemp), 0) = SOCKET_ERROR then begin shutdown(hSocket, SD_BOTH); closesocket(hSocket); WSACleanup; Exit; end; { получаем результат и сохраняем его } FillChar(szBuffer, SizeOf(szBuffer), 0); repeat BuffSize := recv(hSocket, szBuffer, SizeOf(szBuffer), 0); if BuffSize > 0 then begin Result := Result + PAnsiChar(@szBuffer); FillChar(szBuffer, SizeOf(szBuffer), 0); end; until BuffSize > 0; { очищаем буфер, закрываем сокет и выгружаем winsock } FillChar(szBuffer, SizeOf(szBuffer), 0); shutdown(hSocket, SD_BOTH); closesocket(hSocket); WSACleanup; end;
|
Вроде бы все работает нормально. Вслучае неудачного соединения или какой-то ошибки сокет благополучно закрывается. Вопрос следующий. Я хочу скачать текстовый файл с сервера и получить в результате только именно текст, находящийся в этом файле. Естественно приходит информация побольше, содержащая всякие Content-Type, Keep-Alive, Content-Length и какие-то цифры/буквы посреди которых данные с текстового файла. Как мне выцепить только эти данные? На 200 код сделал такую проверку. Кусок кода: | Код | s := GetHttpData('ссылка', 'GET', 80, '', 'Content-Type: text/plain'); if Pos('HTTP/1.1 200 OK', s) > 0 then begin p := Pos(#13#10 + #13#10, s); s := Copy(s, p + 4, Length(s) - p + 4); end else s := 'пусто';
|
Может быть как-то еще можно выполнить проверку на удачность соединения? Или как-то в параметрах подключения у сокетов указать? Спасибо.
|