Здравствуйте.
Мучаюсь над проэктом "полное перенаправление HTTP-запроса (клиент-сервер-клиент)" — фактически аналог прокси сервера (просьба не предлагать переделать через WinInet/сделать прокси) — задача должна быть решена конкретно через Winsock и именно так. Сокеты — блокируемые, мультипоточно.
Значит, тестирую так: есть любой сайт, к примеру тестировал на
http://www.gotovim.ru/ Прописываю в конфиг его домен/айпи, биндю 80 порт на локалхосте и в файл hosts прописываю 127.0.0.1
www.gotovim.ru (соответственно все запросы, которые браузер посылает на домен
www.gotovim.ru приходят на 80 порт loopback ко мне в приложение, и дальше я их и обрабатываю). Обработка — пока что : получение запроса от браузера -> пересылка без изменений на сервер -> получение ответа от сервера -> без изменения передача обратно в браузер (клиенту) — то есть
вообще без изменений пересылка: браузер — приложение — сервер — приложение — браузер. На данный момент это все, что требуется.
Глобальные переменные, относящиеся к коду ниже:
// Variables
WSADATA wsaData; // Winsock object
#define LISTEN_PORT "80" // Listening port
#define DEFAULT_BUFLEN 10240 // Size of buffer
int nClients = 0;//Clients
Код инициализации Winsock, байнд порта, итп — стандартный (MSDN), заканчивается мультипоточным accept:
while(ClientSocket = accept(ListenSocket, (sockaddr *)&client_addr, &client_addr_size))
{
if (ClientSocket == INVALID_SOCKET)
{
#ifdef DEBUG
sprintf_s(errormsg,"accept failed with error: %d\n", WSAGetLastError());
Errorlog(errormsg);
#endif
//TODO - report error
closesocket(ListenSocket);
WSACleanup();
return 1;
}
else
{ //Multithread clients accept
DWORD thID;
CreateThread(NULL, NULL, HandShake, &ClientSocket, NULL, &thID);
nClients++;
WaitForSingleObject(0, 50000);
}
}
в функции HandShake...
// receiving the request
iResult = recv(ClientSocket, recvbuf, DEFAULT_BUFLEN, 0);
if (iResult > 0)
{ // Beginning dialog
recvbuf[iResult] = '\0';
#ifdef DEBUG
Errorlog(recvbuf);
Errorlog("\n-r-\n");
#endif
... далее идёт куча ненужного кода, который пока вообще закомментирован и "непереводимая игра слов на местном диалекте" (с) ....
int isResult3 = 0;
isResult3 = send(fSocketOut, recvbuf, iResult, 0);
if(isResult3)
{
#ifdef DEBUG
Errorlog(recvbuf);
Errorlog("\n-s-\n");
#endif
do
{
iResult = recv(fSocketOut, recvbuf, sizeof(recvbuf), 0);
#ifdef DEBUG
Errorlog(recvbuf);
Errorlog("\n-r-\n");
#endif
int isResult2 = 0;
unsigned int idx = 0;
unsigned long left = iResult;
while (left > 0)
{
isResult2 = send(ClientSocket, &recvbuf[idx], left, 0);
left = left - isResult2;
idx = idx + isResult2;
}
int errt;
errt = WSAGetLastError();//для отладки
#ifdef DEBUG
Errorlog(recvbuf);
Errorlog("\n-s-\n");
#endif
} while (iResult != 0 || iResult != -1 || strcmp(recvbuf, "") != 0);
}
ну и ниже обработка если что-то не то с сокетом (не соединиться и прочее)
else
{
#ifdef DEBUG
Errorlog("Connect fSocketOut failed\n\n");
#endif
nClients--;
closesocket(ClientSocket);
ExitThread(0);
}
Везде использую closesocket по завершению, Значит fSocketOut — сокет, через который коннекчусь к реальному домену, сокет ClientSocket — сокет, через который браузер коннектится ко мне посылая запрос (ну и соответсвенно получает от меня ответ).
Проблема. HTML страница (текст) грузится без проблем. Картинок почти нет (буквально пару баннеров). Когда пробую отдельно загрузить картинку — грузится.
Уже много кружек кофе и гугла прошло, а воз и ныне там.
Какие ошибки были замечены при отладке:
1. Бывает что объем полученных recv данных больше, чем объём данных, переданных send (вот только сегодня узнал, что функция send оказывается может отправить и не весь буффер). Как я понял из той же отладки, цикл
while (left > 0)
{
isResult2 = send(ClientSocket, &recvbuf[idx], left, 0);
left = left - isResult2;
idx = idx + isResult2;
}
это решил. Причем информацию про это нашёл
http://www.rsdn.ru/article/files/progs/inetd.xmlАвтор(ы): Александр Пристенский
Дата: 12.07.2005
Пример реализации inetd для windows представляет собой многопоточный сервер, запускающий дочерние процессы (консольные приложения) ввод-вывод которых перенаправляется на сокет.
вот тут, за что автору огромное спасибо.
2. Иногда в цикле
do{...} while (iResult != 0 || iResult != -1 || strcmp(recvbuf, "") != 0);
при iResult == 0 из цикла не выходит, а продолжает, равно как и при iResult == -1 и strcmp(recvbuf, "") == 0
Также после этого isResult2 часто возвращает -1.
3. Страница (именно текст) — грузится полностью, но в браузере "загрузка" не заканчивается — написано "ожидание ответа от
www.gotovim.ru", а программа при этом уходит в recv который ничего не получает, а, recv, насколько мне известно — функция блокируемая. При этом в лог постоянно пишется пустой буффер recv + send.
4. Самая главная ) как сделать так, чтобы всё работало?
Начал качать исходники браузера, чтобы посмотреть как там реализован цикл "общения" клиент-сервер-клиент, однако исходники очень большие и качаться будут не быстро, судя по всему.
Код вероятно довольно кривой, но как умею... Рабочего решения не прошу, если не затруднит — подскажите, куда копать и где я ошибаюсь (не предлагайте бросить программирование
)?
P.S. Когда открываю небольшую относительно страницу — все грузится и нормально работает.
23.11.11 00:41: Перенесено модератором из 'C/C++' — Кодт