Модераторы: feodorv

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Не работает простой прокси-сервер, Не получается открыть www.ya.ru 
:(
    Опции темы
feodorv
Дата 31.3.2012, 07:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Gwynbleiddd @  25.3.2012,  21:05 Найти цитируемый пост)
Но если размер ответа от сервера будет больше, чем 4096 байт?

Именно!

Цитата(Gwynbleiddd @  25.3.2012,  21:05 Найти цитируемый пост)
Или можно как-то более эффективно организовать приём ответа?

Ну, Вы как-то пытаетесь всё запихнуть в один буфер за один присест. Зачем? Чем стандартная схема плоха:
Код

while( recv(...) ) send(...);

И нет нужды читать по одному байту, можно сразу sizeof(buf) читать. 

Но, опять таки, обращаю Ваше внимание на keep-alive. Если он включён, то одно соездинение может обработать несколько запрос-ответов, и нужно анализировать заголовок Content-Length, чтобы понять, где проходит граница, ну и соединение не закрывать до тех пор, пока Connection не станет closed. Проще keep-alive не поддерживать.


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Gwynbleiddd
Дата 15.4.2012, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 25.3.2008

Репутация: нет
Всего: нет



Переписал частично код, старые проблемы ушли, появились новые ((

С некоторыми сайтами, с тем же www.ya.ru, работает нормально. На всех остальных же выскакивает ошибка "Необработанное исключение в "0x775c15de" в "Proxy.exe": 0xC0000005: Access violation." вот в этом месте:
Код

while ((retval = Recv((SOCKET)hostsocket, &recvbuf2, sizeof(recvbuf2), 1000000)) != 0) // Принимаем ответ хоста на посланный запрос
    {
        recvbuf[i] = recvbuf2;
                ++i;
    }


Правильно ли я понимаю, что ошибка связана с тем, что разные потоки пытаются одновременно работать с recvbuf и recvbuf2?
Как можно исправить её?

Код программы:
Код

// Подключаем необходимые библиотеки
#include "stdafx.h"
#include <winsock2.h>
#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <string.h>
#include <iostream>
#pragma comment (lib, "ws2_32.lib")

// Определяем параметры прокси: порт и ip-адрес
#define PROXY_PORT 7777 // порт прокси
#define PROXY_IP "192.168.126.10" // ip-адрес прокси-сервера

struct Request_key
{
        char User_Agent_k [16]; 
        char Host_k [6]; 
        char Accept_k [10]; 
        char Referer_k [10]; 
        char Accept_Language_k [50]; 
        char Accept_Encoding_k [50]; 
        char Accept_Charset_k [50]; 
        char Cookie_k [10]; 
        char Pragma_k [10];
        char Cache_Control_k [50];
        char Сonnection_k [15];
};

struct Request_value
{
        char Command_v [10]; 
        char URL_v [256]; 
        char Protocol_v [10]; 
        char User_Agent_v [256]; 
        char Host_v [20]; 
        char Accept_v [1024]; 
        char Referer_v [256]; 
        char Accept_Language_v [50]; 
        char Accept_Encoding_v [50]; 
        char Accept_Charset_v [50]; 
        char Cookie_v [4096]; 
        char Pragma_v [20];
        char Cache_Control_v [20];
        char Сonnection_v [20];
        char Host_name [256];
};

int Recv(int unsigned clientsocket, char *recvbuf, int size, int time) //приём данных с помощью select
{
    timeval tm = {0, time}; //задержка, задаётся параметром time
    fd_set fd; //
    FD_ZERO(&fd); //
    FD_SET(clientsocket, &fd); //
    int rc = select(0, &fd, NULL, NULL, &tm); //определяет состояние сокетов. 0 - ничего не делает, &fd - указатель на набор сокетов, которые надо проверить на разрешение на чтение, &tm - задаёт макс время на ожидание? задаётся в timeval
    if(rc == SOCKET_ERROR)
    {
        GetLastError();
        return -1;
    }
    if(rc)
        return recv(clientsocket, recvbuf, size, 0);
}

int GetAddressAndPort (char *str, char *address) 
{
    
    char *p, buf[256], command[5], protocol [10];
    int i, j;
    sscanf (str, "%s%s%s", command, buf, protocol);
    p=strstr(buf,"http://"); //ищем вхождение http:// в нашем массиве buf. если вхождение нашлось, то в p будет указатель на это вхождение.
    //HTTP
    if(p) // если в p не ноль, т.е. в нашем массиве buf всё таки было вхождение http://
    {
        p+=strlen("http://"); //прибавляем к указателю р длину 'http://'
        for(i=0;i<strlen(p);i++) //
            if( *(p+i)=='/') break; //получаем адрес хоста, к которому обращается клиент
        char c = *(p+i);
        *(p+i)=0;
        strcpy(address,p);
        *(p+i) = c;//копируем в переменную address наш указатель p, т.е. как раз адрес сервера
              //default http port 
    } 
        
    return 1;
}

UINT WINAPI Proxy (LPVOID clientsocket)
{
    char recvbuf [10240];
    struct in_addr host2_addr;
    struct sockaddr_in host_addr;
    struct hostent *ht;
    int retval;
    SOCKET hostsocket;
    char *host_name;
    struct Request_value Request_v;
    struct Request_key Request_k;
    struct Request_value Request_m;
    int i = 0;
    char recvbuf2 = NULL;

    hostsocket = socket (AF_INET, SOCK_STREAM, 0);
    if (hostsocket == INVALID_SOCKET)
    {
        printf ("\n Error in New a Socket.");
        WSACleanup();
        return -2;
    }

    printf ("Создан сокет для подключения к хосту\n");

    //while (1)
//    {

    ZeroMemory (&host2_addr, sizeof(host2_addr));
    ZeroMemory (&Request_v, sizeof(Request_v));
    ZeroMemory (&Request_k, sizeof(Request_k));
    ZeroMemory (&Request_m, sizeof(Request_m));
    ZeroMemory (recvbuf, sizeof(recvbuf));
    
    retval = recv ((SOCKET)clientsocket, recvbuf, sizeof(recvbuf), 0);
    printf ("Приняли запрос от клиента\n");
    printf("\n Received %d bytes,data\n[%s]\nfrom client\n\n",retval,recvbuf);
    
    GetAddressAndPort (recvbuf, Request_v.Host_name);
    
    ParserRequest (recvbuf, &Request_k, &Request_v);

    strcpy(Request_m .Сonnection_v, " Close");

    printf ("\nЗАПРОС:\n%s", ss);
    ZeroMemory(&host_name, sizeof(host_name));
    ZeroMemory(&ht, sizeof(ht));
    
    host_name = Request_v.Host_name;
    ht = gethostbyname(host_name);

    //while (ht->h_addr_list[i] != 0)
         host2_addr.s_addr = *(u_long *)ht->h_addr_list[0];
    
    ZeroMemory(&host_addr, sizeof(host_addr));

    host_addr.sin_family = AF_INET; 
    host_addr.sin_addr.s_addr = host2_addr.s_addr; 
    host_addr.sin_port = htons(80);

    if (connect(hostsocket, (struct sockaddr *)&host_addr, sizeof(host_addr)) == SOCKET_ERROR) // Устанавливаем соединение с хостом
    {
        printf ("Connect () Error: %d\n", WSAGetLastError());
        return -1;
    }

    printf ("Установили подключение с хостом\n");
    int retval2;
    retval2 = send(hostsocket, ss, strlen(ss), 0); 
    if(retval2 == SOCKET_ERROR)
    {
        printf ("send () Error: %d\n", WSAGetLastError());
        closesocket (hostsocket);
    }
    printf ("Послали хосту %d bytes от клиента\n", retval2);
    
    i = 0;
    int j = 0;
    char recvbuf3 [10240];
    ZeroMemory (recvbuf, sizeof(recvbuf));
    
    while ((retval = Recv((SOCKET)hostsocket, &recvbuf2, sizeof(recvbuf2), 1000000)) != 0) // Принимаем ответ хоста на посланный запрос
    {
        recvbuf[i] = recvbuf2;
                ++i;
                
    }
    printf ("Получили ответ хоста на запрос\n");
    printf("\n Received %d bytes,data\n[%s]\nfrom server\n", i, recvbuf);

    closesocket (hostsocket);

    printf ("Закрыли соединение с хостом\n");

    retval2 = send ((SOCKET)clientsocket, recvbuf, i, 0);

    if (retval2 == SOCKET_ERROR)
    {
        printf ("send () Error: %d\n", WSAGetLastError());
        closesocket ((SOCKET)clientsocket);
    }
        
    printf ("Послали клиенту %d bytes от хоста\n", retval2);

    //}
     
    closesocket((SOCKET)clientsocket);

    printf ("Закрыли соединение с клиентом\n");
    return 0;
}

int main ()
{

    setlocale (LC_ALL, "Russian");
    WSADATA wsd;
    SOCKET listensocket, clientsocket;
    struct sockaddr_in server_addr, client_addr;
    struct hostent *client;
    UINT IDThread;
    HANDLE proxy_Thread;

    printf ("Прокси-сервер\nIP: %s\nPort: %d\n",PROXY_IP, PROXY_PORT);

    if(WSAStartup (0x101, &wsd) != 0) 
    {
        printf ("\n Error in Startup session.\n");
        WSACleanup();
        return -1;
    } 

    printf ("Библиотека проинициализирована\n");

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY; 
    server_addr.sin_port = htons(PROXY_PORT); 

    listensocket = socket(AF_INET, SOCK_STREAM, 0); 
    if (listensocket == INVALID_SOCKET)
    {
        printf ("\n Error in New a Socket.");
        WSACleanup();
        return -2;
    }
    
    printf ("Создан слушающий сокет\n");
        
    if (bind(listensocket, (struct sockaddr *)&server_addr, sizeof(server_addr)) != 0) 
    {
        printf ("\n Error in Binding socket.");
        WSACleanup();
        return -3;
    }
    
    printf ("Запущено пассивное ожидание подключения\n");

    if (listen (listensocket, 5) != 0) 
    {
        printf ("\n Error in Listen.");
        WSACleanup ();
        return -4;
    }

    printf ("Запущено прослушивание сети, максимум 5 подключений\n");

    int size_of_cli = sizeof(client_addr); 
    while (1)
    {
        clientsocket = accept (listensocket, (struct sockaddr *)&client_addr, &size_of_cli);

        if (clientsocket == INVALID_SOCKET)
        {
            printf ("\nError in Accept");
            WSACleanup();
            return -5;
        }
        else
        {
            printf ("Приняли соединение от клиента\n");
            client = gethostbyaddr ((char *)&client_addr.sin_addr.s_addr, 4, AF_INET);

            proxy_Thread = (HANDLE)_beginthreadex (
                NULL,
                0,
                Proxy,
                (LPVOID) clientsocket,
                NULL,
                &IDThread);
            printf ("Запущен поток для обработка клиента с ID: %d\n", IDThread);
        }
        Sleep (100);
    }
        
    return 1;
                    
}


Дополнительные фцнкции по разбору запроса и созданию нового не стал включать, там всё просто
PM MAIL   Вверх
feodorv
Дата 15.4.2012, 23:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Gwynbleiddd @  15.4.2012,  14:23 Найти цитируемый пост)
На всех остальных же выскакивает ошибка "Необработанное исключение в "0x775c15de" в "Proxy.exe": 0xC0000005: Access violation." вот в этом месте

Ну так нужно же проверять на переполнение:
Код

        recvbuf[i] = recvbuf2;
        ++i;
        if( i >= sizeof(recvbuf) ) break;

А то так можно читать и читать... до access violation))))

PS Смысла читать по-байтово - нет. Совсем нет...


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Gwynbleiddd
Дата 17.4.2012, 21:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 19
Регистрация: 25.3.2008

Репутация: нет
Всего: нет



Переделал. Если не побайтово - то значит вот так? 
Код

while ((retval = Recv((SOCKET)hostsocket, recvbuf, sizeof(recvbuf), 1000000)) != 0) // Принимаем ответ хоста на посланный запрос
    {
        if( retval >= sizeof(recvbuf) ) break; 
        send ((SOCKET)clientsocket, recvbuf, retval, 0);
                    
    }


В таком случае если открываю рамблер или яндекс, то ноут во время загрузки начинает пищать системным динамиком раза 4. А когда сат загрузится, то программа вылетает. Вроде работает, но эти завершения работы непонятные не нравятся (
PM MAIL   Вверх
feodorv
Дата 18.4.2012, 20:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2214
Регистрация: 30.7.2011

Репутация: 10
Всего: 45



Цитата(Gwynbleiddd @  17.4.2012,  22:46 Найти цитируемый пост)
В таком случае если открываю рамблер или яндекс, то ноут во время загрузки начинает пищать системным динамиком раза 4. А когда сат загрузится, то программа вылетает. Вроде работает, но эти завершения работы непонятные не нравятся ( 

Тааак)))
Смотрим подпрограмму Recv:
Код

int Recv(int unsigned clientsocket, char *recvbuf, int size, int time) //приём данных с помощью select
{
    timeval tm = {0, time}; //задержка, задаётся параметром time
    fd_set fd; //
    FD_ZERO(&fd); //
    FD_SET(clientsocket, &fd); //
    int rc = select(0, &fd, NULL, NULL, &tm); //определяет состояние сокетов. 0 - ничего не делает, &fd - указатель на набор сокетов, которые надо проверить на разрешение на чтение, &tm - задаёт макс время на ожидание? задаётся в timeval
    if(rc == SOCKET_ERROR)
    {
        GetLastError();
        return -1;
    }
    if(rc)
        return recv(clientsocket, recvbuf, size, 0);
}

Бог с ним, что в виндах используется select и всё такое.

Интересно, а Вы смотрите на предупреждения, которые выдаёт компилятор?))) Если rc не 0, то return recv(clientsocket, recvbuf, size, 0); - очень хорошо. А если 0, то что возвращается? Мусор?


Если rc случилась в виде SOCKET_ERROR, то возвращается -1, допустим. return recv(...), допустим. Но как это совмещается с таким использованием Recv:
Код

while ((retval = Recv((SOCKET)hostsocket, recvbuf, sizeof(recvbuf), 1000000)) != 0) // Принимаем ответ хоста на посланный запрос
  ...

Если из Recv вернётся -1 или SOCKET_ERROR, то цикл продолжится, а в его теле:
Код

int retval;
...
       if( retval >= sizeof(recvbuf) ) break; 
        send ((SOCKET)clientsocket, recvbuf, retval, 0);

 smile 


--------------------
Напильник, велосипед, грабли и костыли - основные инструменты программиста...
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Сети | Следующая тема »


 




[ Время генерации скрипта: 0.0479 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.