Форум: "Прочее";
Текущий архив: 2008.03.23;
Скачать: [xml.tar.bz2];
Внизсокеты на winapi Найти похожие ветки
← →
Dmitry S © (2008-01-20 12:12) [0]Написал такую функцию. Делает простой запрос к HTTP серверу и возвращает ответ вместе с заголовками (или пустую строку, если ошибка):
function Query(host, uri:string; Method:string = "GET"; Data:string = ""):string;
var
MySocket:TSocket;
Addr:TSockAddr;
HostEnt:PHostEnt;
Buf:PChar;
Text, S:String;
Num: Integer;
begin
Result := "";
// Получаем IP
HostEnt := gethostbyname(PChar(host));
if HostEnt = nil then Exit;
if HostEnt.h_length < 4 then Exit;
// Устанавливаем адрес
Addr.sin_family := AF_INET;
Addr.sin_port := htons(80); // http
CopyMemory(@Addr.sin_addr, HostEnt^.h_addr^, 4);
FillMemory(@Addr.sin_zero, 8, 0);
// Создаем сокет
MySocket := socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if MySocket = INVALID_SOCKET then Exit;
// Канектим его
Num := connect(MySocket, Addr, sizeof(Addr));
if Num = SOCKET_ERROR then
begin
closesocket(MySocket);
Exit;
end;
// Подготавливаем запрос
Text :=
Method + " " + uri + " HTTP/1.0"#13#10 +
"Host: " + host + #13#10 +
"Connection: Close" + #13#10;
if Method = "POST" then
begin
Str(Length(Data), S);
Text := Text +
"Content-Type: application/x-www-form-urlencoded"#13#10 +
"Content-Length: " + S + #13#10#13#10 + Data;
end
else
begin
Text := Text +#13#10;
end;
// Посылаем запрос
while true do
begin
Num := send(MySocket, PChar(Text)^, Length(Text), 0);
if Num = SOCKET_ERROR then
begin
closesocket(MySocket);
Exit;
end;
if Num = 0 then sleep(100);
if Num = Length(Text) then break;
Delete(Text, 1, Num);
end;
// Получаем ответ
GetMem(Buf, 1024);
FillMemory(Buf, 1024, 0);
while true do
begin
Num := recv(MySocket, Buf^, 1023, 0);
if Num = SOCKET_ERROR then
begin
closesocket(MySocket);
Result := "";
FreeMem(Buf);
Exit;
end;
if Num = 0 then break;
Result := Result + Buf;
FillMemory(Buf, 1024, 0);
end;
FreeMem(Buf);
closesocket(MySocket);
end;
Все ли правильно?
Меня интересует момент:
HostEnt := gethostbyname(PChar(host));
По идее gethostbyname выделяет память под ответ, но она нигде не освобождается. Как и где ее освобождать, чтобы не вызвать утечки?
Ну и в остальном правильно ли ?
← →
Dmitry S © (2008-01-20 12:15) [1]Правильно ли я сделал работаю с функцией send? Сокет по умолчанию ведь должен быть блокирующемся. И вот я не знаю заблокируется ли он до тех пока сам все не отправит, или нужно ему "помогать" как я это сделал.
← →
DVM © (2008-01-20 12:24) [2]
> По идее gethostbyname выделяет память под ответ, но она
> нигде не освобождается. Как и где ее освобождать, чтобы
> не вызвать утечки?
Справку читал?The pointer which is returned points to a structure which is allocated by Windows Sockets. The application must never attempt to modify this structure or to free any of its components. Furthermore, only one copy of this structure is allocated per thread, and so the application should copy any information which it needs before issuing any other Windows Sockets function calls.
← →
Dmitry S © (2008-01-20 12:28) [3]
> DVM ©
читал... Но ведь я таких вызовов могу сделать сколь угодно много, и тем самым закончу память. Я ведь даже нигде не указываю, что больше не хочу работать с этой структурой. Винда ее вечно чтоли будет хранить?
← →
DVM © (2008-01-20 12:30) [4]
> читал... Но ведь я таких вызовов могу сделать сколь угодно
> много, и тем самым закончу память.
читай еще, но теперь внимательно.
← →
DVM © (2008-01-20 12:36) [5]кстати, лучше так вот наверное:
function InetAddr(const AHost: string): integer;
var
PHost:PChar;
HostEnt: PHostEnt;
begin
if AHost = "" then
result := INADDR_NONE
else
begin
PHost := PChar(AHost);
Result := inet_addr(PHost);
if Result = INADDR_NONE then
begin
HostEnt := GetHostByName(PHost);
if HostEnt <> nil then
Result := integer(pointer(HostEnt^.h_addr^)^);
end;
end;
end;
И потомAddr.sin_addr.s_addr := InetAddr(Host);
← →
Dmitry S © (2008-01-20 12:59) [6]А все понял... Одна на поток.
А чем твой способ лучше?
← →
DVM © (2008-01-20 13:12) [7]
> А чем твой способ лучше?
на вход можно подать как IP так и имя - результат будт один s_addr.
И все вот эти строки твои:
CopyMemory(@Addr.sin_addr, HostEnt^.h_addr^, 4);
FillMemory(@Addr.sin_zero, 8, 0);
не нужны.
← →
DVM © (2008-01-20 13:13) [8]
> А все понял... Одна на поток.
А память будет освобождена скорее всего вызовом WSACleanUp
← →
Dmitry S © (2008-01-20 13:45) [9]А WSACleanUp надо вызывать в конце работы процесса или потока?
← →
DVM © (2008-01-20 14:05) [10]
> Dmitry S © (20.01.08 13:45) [9]
WsaErr := WSAStartUp($0101, Wsa);
if WsaErr = 0 then
begin
try
... тут работает с сетью ...
finally
WSACleanUp;
end;
end
Т.е. в том же потоке, что и WSAStartUp
← →
Dmitry S © (2008-01-20 14:20) [11]Еще два вопроса тогда...
1. $0101 обязательно? я использую вторую версию, это ничего страшного?
2. Вобщем то приложение у меня такое:
Есть основной поток с формами и прочим. И есть дополнительный поток, который создается только для того чтобы получить данные с сервера. Затем его убивают, и через некоторое время создают заново. Потом после того как он получил данные его опять убивают. И так далее, пока пользователь не закроет программу.
В данном случае я должен в каждом новом потоке выполнять WSAStartUp и WSACleanUp? Или один раз при старте и завершении приложения?
← →
DVM © (2008-01-20 14:27) [12]
> 1. $0101 обязательно? я использую вторую версию, это ничего
> страшного?
Тогда ставь свою версию место этого
> В данном случае я должен в каждом новом потоке выполнять
> WSAStartUp и WSACleanUp?
да
← →
ketmar © (2008-01-20 17:06) [13]>[12] DVM©(20.01.08 14:27)
а нафига? завсегда хватало один раз на всех…
← →
DVM © (2008-01-20 17:27) [14]
> ketmar © (20.01.08 17:06) [13]
Конечно достаточно вызвать один раз WSAStartUp и один раз WSACleanUp на весь процесс, главное, чтобы количество вызовов WSAStartUp и WSACleanUp совпадало. Просто бывает иногда удобнее (случай автора вопроса имхо) отделить код ответственный за работу с сокетами в отдельный модуль. Например, в модуль в котором описан класс потока. Тогда и WSAStartUp и WSACleanUp лучше разместить там. И ничего страшного, что вызовов будет несколько, зато обе функции будут находиться рядом.
Есть еще правда вариант с initialization / finalization модуля.
← →
ketmar © (2008-01-20 17:35) [15]>[14] DVM©(20.01.08 17:27)
>Есть еще правда вариант с initialization / finalization модуля.
как я лично завсегда и делал. %-)
← →
ketmar © (2008-01-20 17:36) [16]вру. не завсегда. таки потом выделил в отдельные процедуры и вызывал руками. потому что инициализация сокетов — процесс долгий, а были ситуации, кодга оно до работы с сетью просто и не доживало, но при этом запускалось часто-часто.
← →
wp2 © (2008-01-20 23:10) [17]>if HostEnt.h_length < 4 then Exit;
впервые вижу такое...
← →
DVM © (2008-01-20 23:18) [18]
> впервые вижу такое...
Это чтобы не нарваться на адреса IPv3 и ниже вероятно :)
← →
Dmitry S © (2008-02-09 11:37) [19]
> впервые вижу такое...
На случай, если адресов не будет: 0 < 4 ;)
Страницы: 1 вся ветка
Форум: "Прочее";
Текущий архив: 2008.03.23;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.006 c