HTTP Winsock
От: my_problem  
Дата: 22.11.11 18:39
Оценка:
Здравствуйте.

Мучаюсь над проэктом "полное перенаправление 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++' — Кодт
http redirect winsock vc
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.