C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

 
Помогите новичку в сокетах
assmer
Отправлено: 04.03.2006, 10:59


Ученик-кочегар

Группа: Участник
Сообщений: 3



Если у кого ни будь есть возможность, выложите пожалуйста рабочий код функции которая используя API подключалась бы к какому ни будь сайту и скачивала с него какую ни будь страницу. Заранее благодарен.
AVC
Отправлено: 06.03.2006, 10:48


Ветеран

Группа: Модератор
Сообщений: 1583



CODE

//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
// Загрузка страницы через сокеты
//---------------------------------------------------------------------------

void __fastcall TForm1::Bt_GetSiteClick(TObject *Sender)
{
AxSock_Init();
SOCKET mysocket = INVALID_SOCKET;

AnsiString text = AnsiString("") + "\
GET [URL=http://www.cbuilder.ru/forums/index.php]http://www.cbuilder.ru/forums/index.php[/URL] HTTP/1.0\r\n\
Accept: */*\r\n\
Accept-Language: ru\r\n\
Pragma: no-cache\r\n\
User-Agent: XXX\r\n\
Host: www.cbuilder.ru\r\n\
Proxy-Connection: Keep-Alive\r\n\
\r\n\
\r\n\
";

try { // 240 — мой прокси, ходим черз порт 8080
text = PostExecute(mysocket, "10.111.96.240", 8080, text, 6000);
}
catch (Exception &xcp) { ShowMessage(xcp.Message); }

Memo1->Lines->Text = text;

if (mysocket != INVALID_SOCKET)
{ closesocket(mysocket);
mysocket = INVALID_SOCKET;
}
AxSock_DeInit();
}

//---------------------------------------------------------------------------
// Выполнить отправку и дождаться ответа
//---------------------------------------------------------------------------

AnsiString __fastcall TForm1::PostExecute (SOCKET& pSocket
,const AnsiString& IP
,int Port
,const AnsiString &PostText
,int waitms // ждать овет ms 0-не ждать
)
{
int ret;
if (pSocket != INVALID_SOCKET)
{ closesocket(pSocket);
pSocket = INVALID_SOCKET;
}

// AF_INET SOCK_STREAM/SOCK_DGRAM ... _UDP/_IP/_TCP
pSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


if (pSocket == INVALID_SOCKET) throw Exception(" socket error " + WSAErrorAsText());


// Устанавливаем предельное время ожидания ответа
int timeout = 3000;
if (waitms > 0) timeout = waitms;

setsockopt(pSocket, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout, sizeof(timeout));

sockaddr_in sadr_trg;
sadr_trg.sin_family = AF_INET;
sadr_trg.sin_addr.s_addr = inet_addr(IP.c_str());
sadr_trg.sin_port = htons (Port);

ret = connect(pSocket, (sockaddr*)&sadr_trg, sizeof(sadr_trg));
if (ret == SOCKET_ERROR) throw Exception(" connect error " + WSAErrorAsText());



ret = send(pSocket, PostText.c_str(), PostText.Length(), 0);
if (ret == SOCKET_ERROR) throw Exception(" send error " + WSAErrorAsText());


AnsiString answertext = "";
if (waitms > 0)
{ char buf[0xFFF0]; memset(buf, 0x00, sizeof(buf));
int rcou = 0;
int retr = recv(pSocket, buf, sizeof(buf), 0 /*MSG_PEEK*/);
if (retr == SOCKET_ERROR)
{ AnsiString errmsg = " recv error " + WSAErrorAsText();
closesocket(pSocket); pSocket = INVALID_SOCKET;
throw Exception(errmsg);
}
while(retr > 0)
{ rcou += retr;
retr = recv(pSocket, buf+rcou, sizeof(buf) — rcou, 0);

// надо более строгий анализ на версию протокола, но не в этом проекте
// для HTTP/1.1 и chunced в конце текста html стоит 0D0A300D0A0D0A
if ((buf[rcou+retr-7] & 0xFF) == 0x0D &&
(buf[rcou+retr-6] & 0xFF) == 0x0A &&
(buf[rcou+retr-5] & 0xFF) == 0x30 &&
(buf[rcou+retr-4] & 0xFF) == 0x0D &&
(buf[rcou+retr-3] & 0xFF) == 0x0A &&
(buf[rcou+retr-2] & 0xFF) == 0x0D &&
(buf[rcou+retr-1] & 0xFF) == 0x0A )
{
break;
}
}
answertext = AnsiString(buf);
}

ret = closesocket(pSocket);
if (ret == SOCKET_ERROR) throw Exception(" close connect error " + WSAErrorAsText());

pSocket = INVALID_SOCKET;
return answertext;
}

//---------------------------------------------------------------------------

Функции AxSock_Init / Deinit — просто инициализация библиотеки сокетов. Естественно у меня это все выделено в отдельный модуль, просто подключаемый к проекту. Так же в тексте используются переменные и функции из этого модуля. Их смысл понятен из названия. Будет что не ясно — спрашивайте.

Для получения ВСЕЙ страницы нужно проанализировать полученный текст и выполнить все необходимые ссылки (типа css, js и прочее).

Отредактировано AVC — 09/03/2006, 08:05
assmer
Отправлено: 06.03.2006, 22:36


Ученик-кочегар

Группа: Участник
Сообщений: 3



ret = bind (pSocket, (sockaddr*)&sadr_src, sizeof(sadr_src));

А разве в этой строчке есть необходимость, мне кто то говорил что bind нужна только в случае создания сервера.
_NIK_
Отправлено: 07.03.2006, 01:53


Дежурный стрелочник

Группа: Участник
Сообщений: 55



QUOTE (assmer @ 06/03/2006, 22:36)
ret = bind (pSocket, (sockaddr*)&sadr_src, sizeof(sadr_src));

А разве в этой строчке есть необходимость, мне кто то говорил что bind нужна только в случае создания сервера.

Bind нужна и для сервера и для клиента — основная функция создания сокета — она связывает переменную SOCKET и непосредственно глобальный идентификатор на тачке, после кот. появляется порт!
Guest
Отправлено: 07.03.2006, 10:09


Не зарегистрирован







Что то у меня не выходит может из за того что сделал некотороые замены:
- Заменил AxSock_Init() на :
WSADATA WS;
WSAStartup(0x101,&WS);

- Заменил WSAErrorAsText на WSAGetLastError() (у меня ту функцию не понимает и Help её не знает)

- Заменил перед вызовом (bind)
sadr_src.sin_addr.s_addr = inet_addr(AxS_LocalIP.c_str());
на
sadr_src.sin_addr.s_addr = INADDR_ANY;
(Не понимает AxS_LocalIP)

- Если ставить порт 8080 то вообще не конектица если ставить порт 80 то конектица но ни чего на запросы не отвечает.
AVC
Отправлено: 07.03.2006, 11:46


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

ret = bind (pSocket, (sockaddr*)&sadr_src, sizeof(sadr_src));

А разве в этой строчке есть необходимость

Да, спасибо, не нужна. Затесалась от НЕ ориентированного на соединение клиента. biggrin.gif

QUOTE

мне кто то говорил что bind нужна только в случае создания сервера.

Это не вся правда о bind. smile.gif
AVC
Отправлено: 07.03.2006, 12:02


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE

Если ставить порт 8080 то вообще не конектица если ставить порт 80 то конектица но ни чего на запросы не отвечает.

В примере МОЙ прокси и МОЙ порт на прокси. У вас свои.

QUOTE

Что то у меня не выходит может из за того что сделал некотороые замены:

Прикрепляю библиотечный модуль, если подойти творчески — все должно получиться. Не выйдет — сделаю отдельным проектом.

Подозреваю нет ответа из-за AxS_LocalIP это МОЙ IP адрес, надо было подставить свой.

User Attached Image Скачать файл
assmer.rar


assmer
Отправлено: 07.03.2006, 13:39


Ученик-кочегар

Группа: Участник
Сообщений: 3



Если не нужен bind тогда не нужена и структура sadr_src а значит не пригодится и AxS_LocalIP так что не он причина, причина в чем то еще.
AVC
Отправлено: 09.03.2006, 09:03


Ветеран

Группа: Модератор
Сообщений: 1583



QUOTE (assmer @ 07/03/2006, 12:39)
Если не нужен bind  тогда не нужена и структура sadr_src а значит не пригодится и AxS_LocalIP так что не он причина, причина в чем то еще.

Справедливо. Но этот код (даже в исходном виде, с bind) у меня реально работает как в рамках локальной сети — для опроса некоторых устройств, поддерживающих http; в корпоративной сети — получение информации от сервереров; опробован, но пока не пригодился, в глобальной сети.

Чем еше помочь не знаю. Посмотрите настройки сети. А может не правильно сформулирован запрос? Поставьте снифер, снимите протокол при доступе через web-browser, посмотрите запросы и ответы.
Или давайте ваш запрос — попробую выполнить у себя.

Кстати, посмотрите на содержимое строки запроса — GET. В в оригинале она выглядит несколькр иначе (происки движка форума smile.gif )

Вернуться в Вопросы программирования в C++Builder