Отбрасывание пакетов прокси-сервера

Итак, я пишу прокси-сервер (следуя руководству Beej по сетевому программированию), и теперь я наткнулся на проблему. Кажется, я не могу решить ... Вождение меня с ума ..

Проблема заключается в том, что он упаковывает некоторые пакеты из-за «Сброс соединения через peer», когда он собирается пересылать пакеты веб-клиенту.

Вот полный код.

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

string replace_string(string str, const string from, const string to) {
    size_t start_pos = str.find(from);
    if(start_pos == string::npos)
        return str;
    str.replace(start_pos, from.length(), to);
    return str;
}

void sigchld_handler(int s)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
}
class Server
{
private:
    string PORT;
    int MAXDATASIZE;
public:
    Server()
    {
        PORT = "3490";
        MAXDATASIZE = 4096;

    }



   //get sockaddr, IPv4 or IPv6:
    void *get_in_addr(struct sockaddr *sa)
    {
        if (sa->sa_family == AF_INET) {
            return &(((struct sockaddr_in*)sa)->sin_addr);
        }

        return &(((struct sockaddr_in6*)sa)->sin6_addr);
    }

    int start_server()
    {

       //first, load up address structs with getaddrinfo():
        int socketfd, new_socketfd;
        struct addrinfo hints, *servinfo, *p;
        struct sockaddr_storage their_addr;
        socklen_t their_addr_size, addr_size;
        struct sigaction sa;

        char s[INET6_ADDRSTRLEN];

        int rv;
        int yes = 1;
        int BACKLOG = 10;
        int numbytes;
        unsigned char buf[MAXDATASIZE];

        memset(&hints, 0, sizeof hints);//Make sure it is cleared
        hints.ai_family = AF_UNSPEC;    //use IPv4 or IPv6, whichever
        hints.ai_socktype = SOCK_STREAM;//TCP socket
        hints.ai_flags = AI_PASSIVE;    //fill in my IP for me

        if ((rv = getaddrinfo(NULL, PORT.c_str(), &hints, &servinfo)) != 0) {
            cerr << "getaddrinfo: " << gai_strerror(rv) << endl;
            return -1;
        }

       //make a socket, bind it asap
        for(p = servinfo; p != NULL; p = p->ai_next)
        {
            if ((socketfd = socket(p->ai_family, p->ai_socktype,
                                   p->ai_protocol)) == -1) {
                //perror("server: socket");
                cerr << "ERROR: Server: socket" << endl;
                continue;
            }

            if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes,
                           sizeof(int)) == -1) {
                //perror("setsockopt");
                cerr << "ERROR: setsockopt" << endl;
                exit(1);
            }

            if (bind(socketfd, p->ai_addr, p->ai_addrlen) == -1) {
                close(socketfd);
                //perror("server: bind");
                cerr << "ERROR: server: bind" << endl;
                continue;
            }
            break;  
        }
        //If the binding failed
        if ( p == NULL)
        {
            cerr << "Server: failed to bind" << endl;
            return -1;
        }

        //Free space, we do not need it anymore.
        freeaddrinfo(servinfo);

        //Listen to the socket (port)
        if ( listen(socketfd, BACKLOG) == -1)
        {
            cerr << "ERROR: listen" << endl;
        }

       //killing zombie processs (all dead processes)
        sa.sa_handler = sigchld_handler; 
        sigemptyset(&sa.sa_mask);
        sa.sa_flags = SA_RESTART;
        if (sigaction(SIGCHLD, &sa, NULL) == -1) {
            perror("sigaction");
            exit(1);
        }

        cout << "Server: waiting for connections ...\n"<(buf), MAXDATASIZE);  //Convert to unsigned char array to make it easier to handle                              
                buffer_str = replace_string(buffer_str, "Proxy-Connection: keep-alive","Connection: close");//Make it connection Close instead of Keep-Alive
                buffer_str = replace_string(buffer_str, "Connection: keep-alive","Connection: close");//Make it connection Close instead of Keep-Alive
               //removes host from GET, and saves it
                int first = buffer_str.find_first_of("/");                      
                int last =  buffer_str.find_first_of("/", first+2);
                int size_of_buf=buffer_str.size();
                unsigned char host_request[MAXDATASIZE];
                for (int a=0;a<=size_of_buf;a++)
                    host_request[a]=buffer_str[a];
                host_request[size_of_buf]='\0';
                string host_name = "";
                for(int i=first+2;iai_next) {
                    if ((host_sockfd = socket(host_p->ai_family, host_p->ai_socktype,
                                              host_p->ai_protocol)) == -1) {
                        perror("client: socket");
                        continue;
                    }

                    if (connect(host_sockfd, host_p->ai_addr, host_p->ai_addrlen) == -1) {
                        close(host_sockfd);
                        perror("client: connect");
                        continue;
                    }

                    break;
                }

                if (host_p == NULL) {
                    fprintf(stderr, "client: failed to connect\n");
                    return 2;
                }

                inet_ntop(host_p->ai_family, get_in_addr((struct sockaddr *)host_p->ai_addr),s, sizeof s); //Converts the IP address from binary to IPv4/6-format
                //printf("client: connecting to %s\n", s);

                freeaddrinfo(host_servinfo);//all done with this structure

                /*Send the GET request to the server*/
                send_message(host_sockfd, host_request, sizeof(host_request), "Webserver");
                if (!fork())
                {
                    memset(&host_buf, 0, MAXDATASIZE);
                    while (recv(host_sockfd, &host_buf, MAXDATASIZE, 0) > 0 ) {
                        close(socketfd);

                        send_message(new_socketfd, (unsigned char *)host_buf, MAXDATASIZE, "Browser");
                        memset(&host_buf, 0, MAXDATASIZE);
                    }

                }

                close(host_sockfd);
            }


            //cout << "server: got connection from " << s << endl;

            close(new_socketfd); //parent doesn't need this

        }

        return 1;
    }
    int send_message(int &socket,unsigned char msg[], int length, string too)
    {
        usleep(10);
        if (send(socket, msg, length, 0) == -1)
        {
            cerr << "ERROR: sending to " << too << endl;
            cerr << "We will lose a packet due to" << endl;
            perror("send");
            cerr << "-------------------MEDDELANDE-------------------\n\n" << msg << endl << 
                "--------------------------------------------------\n\n";
            return -1;
        }
        return 1;
    }
};

int main()
{
    Server srv;
    srv.start_server();
}

Есть идеи? Заранее спасибо!

0
nl ja de
«Сброс соединения сверстником», вероятно, означает, что пользователь закрыл окно браузера или нажал кнопку «Стоп».
добавлено автор Barmar, источник
@thang Нет, «сброс соединения сверстником» означает, что он отправил RST, а не FIN. Или ты снова шутишь? В любом случае остановите его. Решение состоит в том, чтобы закрыть соединение и забыть об этом. Через минуту будет еще один.
добавлено автор EJP, источник
@DanAndreasson Как только вы получите какую-либо ошибку, кроме таймаута чтения.
добавлено автор EJP, источник
@DanAndreasson Итак, у вас есть еще одна проблема в дополнение к тому, как обрабатывать сбросы. Я не могу полностью понять ваш цикл копирования данных. Он закрывает слуховой сокет каждый раз, когда вы получаете данные, и он не использует количество отсчетов чтения, возвращаемое recv ();
добавлено автор EJP, источник
Используйте его как аргумент length для отправки (): while ((rc = recv (infd, buffer, 0, BUFFERSIZE, 0))> 0) {send (outfd, buffer, 0 , rc, 0); } . В противном случае вы пишете случайный мусор в конце каждого буфера. Вы также можете избавиться от memset() в этом цикле по той же причине.
добавлено автор EJP, источник
почему бы вам не отследить его с помощью wirehark и опубликовать результаты.
добавлено автор thang, источник
это когда другая сторона отправила RST ( stackoverflow.com/questions/1434451/ соединение-сброс-на-пи & ZWNJ; г )
добавлено автор thang, источник
по моему опыту, это может быть связано с брандмауэром ... или сбой в другой стороне
добавлено автор thang, источник
вы должны понять, почему вы сначала получаете RST ... может быть, только что кто-то остановил веб-клиента, пока пакеты не ожидали. и в этом случае вам не нужно ничего делать, и вы не можете сделать ничего. просто выключите соединение и закройте сокет.
добавлено автор thang, источник
@EJP Что мне делать с показанием чтения, возвращаемым recv ()?
добавлено автор Dan Andreasson, источник
@EJP Это не исправляет мою проблему. Когда я подключен к прокси-серверу, любой веб-сайт, который я вводил, выглядит запутанно испорченным, картинки скрипят и содержимое отсутствует.
добавлено автор Dan Andreasson, источник
@EJP Когда вы предложите мне закрыть соединение?
добавлено автор Dan Andreasson, источник
@thang Насколько велики были бы вы рекомендовать пакеты?
добавлено автор Dan Andreasson, источник
Сейчас я запускаю его на локальном хосте. Я не закрываю браузер или не останавливаю
добавлено автор Dan Andreasson, источник

2 ответы

Код не очень похож на руководство Beejs, которое я помню. C ++ - это не моя самая сильная сторона, но мне кажется, что вы не отслеживаете количество данных, записанных или прочитанных из сокетов. Неудивительно, что данные отсутствуют.

У вас есть close() внутри вашего времени (почему?) И sleep() в вашем send_message и т. Д. Всякий раз, когда вы оказываете себе сон (), чтобы немного работать, это, как правило, ошибка.

EDIT: Чтобы быть более конструктивным, я предлагаю вам скопировать sendall() из руководства Beejs. Отслеживайте, сколько данных recv() дает вам и отправляет их с помощью sendall.

Для возможного улучшения скорости отслеживайте количество полученных и отправленных данных и будьте осторожны, чтобы не блокировать ожидание отправки буфера отправки.

EDIT2: Also add an exit to the child process. Now it runs into the parent code, when its done with the recv & send loop. It looks like you meant it to stay inside the if(!fork()) but currently it does not.

2
добавлено
У меня не было времени просмотреть весь код сейчас, но два быстрых наблюдения. 1) recv() может вернуть 0. Это означает, что писать клиенту больше нечего, и вы должны выйти из него упорядоченным образом. См. Man-страницу для получения подробной информации о возвращаемых значениях. 2) Возьмите возвращаемое значение recv() непосредственно в переменную. Теперь вы делаете strlen в буфере приема. Это не будет работать надежно. Переданные данные могут содержать то, что равно «null» для strlen. Выходы (), похоже, находятся в хороших местах, хотя условие для первого должно также учитывать 0 (как упоминалось ранее).
добавлено автор thuovila, источник
pastebin.com/HDgdjruE Что-то в этом роде? Он все еще не работает хорошо :(
добавлено автор Dan Andreasson, источник

Я решил проблему, с помощью некоторых парней!

Первое, что мне пришлось изменить, - обменять sizeof на strlen в recv ().

Secondly I didn't store the size of the data received by recv, so when I forwarded the received data from the webserver to the webbrowser I said that the packet contained MAXDATASIZE. The fix for this problem was to store the data received and then just give that size as a parameter in the send()

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

Спасибо всем, кто помог мне прийти к этим решениям! Особенно Thuovila!

0
добавлено
Я рад, что ты это понял. Последний код (на pastebin.org) был настолько длинным, что я никогда не обходил его подробно. Что касается recv (), я бы порекомендовал получить длину данных следующим образом: int bytes_received = recv (...) , а также обрабатывать значения 0 и <0.
добавлено автор thuovila, источник
Вот что я делаю сейчас. Я немного поработал над настройкой кода, разделил его на функции и т. Д. Я буду публиковать код, когда он будет закончен. Еще раз спасибо за помощь!
добавлено автор Dan Andreasson, источник
pro.cxx
pro.cxx
3 049 участник(ов)

C/C++ chat 0. Простые вопросы, лабы и о IDE — в чат новичков @supapro 1. Не хамим, не переходим на личности, не вбрасываем утверждения без доказательств 2. No Ads, offtop, flood Объявления о вакансиях и евенты - в лс @AlexFails https://t.me/ProCxx/259155

supapro.cxx
supapro.cxx
1 925 участник(ов)

Чат для тех, кто немного знает C++, простые вопросы по реализации, синтаксису и ide – сюда, а для другого есть: /Главный чат по серьезным вопросам — @ProCxx /Чат по обсуждению всего — @fludpac

ntwrk
ntwrk
1 773 участник(ов)

Группа для сетевых инженеров Создатель группы: @HelloSadness Админы: @darwinggl @mxssl @Sk1f3r @blademd @gngbng

RU.SYSADMIN — Олды здесь?
RU.SYSADMIN — Олды здесь?
1 616 участник(ов)

Ламповая конференция сисадминов! Правила: http://telegra.ph/Pravila-ru-sysadmin-12-01 Список интересных групп и каналов: https://github.com/goq/telegram-list

Pro Telecom
Pro Telecom
884 участник(ов)

Добро пожаловать, связисты! Запрещена реклама чатов Cообщество для своих - https://www.facebook.com/groups/protelecom/ https://vk.com/telecomrf

C++ Russia
C++ Russia
384 участник(ов)

Сообщество разработчиков C++ в Telegram.

pro.enterprise
pro.enterprise
346 участник(ов)

Темы обсуждения: Сервера, системы хранения данных, hardware, software, сети хранения данных, сетевое оборудование, облачные инфраструктуры и никакой политики.

cxx.Дискуссионная
cxx.Дискуссионная
298 участник(ов)

это не двач, общайтесь вежливо; разговор на почти любые темы; Не согласны с баном? В лс @AlexFails, @ivario

C++ для маленьких и тупых
C++ для маленьких и тупых
105 участник(ов)

Лоу левел (по среднему IQ участников) чатик ExtremeCode @extremecode Флудилка @extremecode_rest