Сокет-сервер с epoll выдает неизвестные байты при отключении - PullRequest
0 голосов
/ 24 января 2012

У меня есть сервер сокетов в C ++, и я использую epoll.Я отправляю на сервер символ, содержащий HeaderPacket и NormalPacket.Сначала я читаю HeaderPacket, а затем я читаю NormalPacket.

И теперь проблема, когда я закрываю клиент (я пытался использовать close и shutdown - тот же вывод), я получаю несколько странных байтов напервый recv (тот, который читает пакет заголовка) и после этой ошибки сегментации.

Кроме того, когда я изменяю размер моего содержимого char с HeaderPacket на другое значение, например 120, я не получаю ошибку сегментациино когда я устанавливаю его на 40 или другое значение, я получаю ошибку сегментации.

#define BUFFERSIZE 256
#define CHARSIZE 40

Вот функция, которую я использую для чтения:

void PacketHandler::ReadBytes(int fd, struct HeaderPacket &hp, char buffer[])

{

    int reading = 0;

    ssize_t hpCount, cpCount;

    char hpBuffer[6];



    hpCount = recv(fd, hpBuffer, 6, 0);

    if(hpCount <= 0)

    {

       reading = 1;

    } else {  

        this->UnserializeHeaderPacket(hpBuffer, hp);

        print(DEBUG, Helpers::IntegerToString(hp.length)); 

        cpCount = hp.length;

        char cpBuffer[cpCount];

        memset(cpBuffer, 0, sizeof(cpBuffer));

        char* iterator = cpBuffer;

        int bytesLeft = sizeof(cpBuffer) - sizeof(char);

        print(DEBUG, Helpers::IntegerToString(bytesLeft)); 

        if(bytesLeft < 0)

        {

            reading = 1;

        }

        while(bytesLeft > 0)

        {

            ssize_t curr;

            curr = recv(fd, iterator, bytesLeft, 0);



            if(curr == -1)

            {

                if(errno != EAGAIN)

                {

                    reading = 1;

                    print(WARNING, "reading error at content packet");

                }

                break;

            } else if(curr == 0) {

                reading = 1;

                break;

            } 



            iterator += curr;

            bytesLeft -= curr;                 





        }



            memcpy(buffer, cpBuffer, sizeof cpBuffer);     

    }



    if(reading)

    {

        print(NOTICE, "Closed connection with the descriptor " + Helpers::IntegerToString(fd));

        close(fd);

    }

}

Вот функция для epoll

void EventHandler::RunningLoop(int fd)

{

    while(1)

    {

        int availableEvents, i;



        availableEvents = epoll_wait(this->efd, this->events, MAXEVENTS, -1);

        for(i = 0; i < availableEvents; i++)

        {

            if(this->events[i].data.fd == fd)

            {

                // Accepting new connection

                this->AcceptClient(fd);

                continue;

            }

            else if((this->events[i].events & EPOLLERR) || (this->events[i].events & EPOLLHUP) || (!(this->events[i].events & EPOLLIN)))

            {

                print(WARNING, "epoll error on reading from fd");

                close (this->events[i].data.fd);

                continue;

            } 

            else if(this->events[i].events & EPOLLRDHUP) 

            {

                print(WARNING, "intern close socket");

                close (this->events[i].data.fd);



            } else {

                // Reading packets

                this->run->InitializePacket(this->events[i].data.fd); // cals the read function

            }

        }

    }



    free(this->events);

    close(fd);

}

Мои пакеты:

struct HeaderPacket

{

    uint16_t opcode;

    uint32_t length;

};



struct HelloWorldPacket

{

    uint16_t byteOrder;

    char content[CHARSIZE];

};

Функция для сериализации:

void PacketHandler::SerializeHeaderPacket(HeaderPacket packet, char buffer[])

{

    uint16_t u16;

    uint32_t u32;



    u16 = htons(packet.opcode);

    memcpy(buffer+0, &u16, 2);

    u32 = htonl(packet.length);

    memcpy(buffer+2, &u32, 4);

}



void PacketHandler::UnserializeHeaderPacket(char buffer[], HeaderPacket &packet)

{

    uint16_t u16;

    uint32_t u32;



    memcpy(&u16, buffer+0, 2);

    packet.opcode = ntohs(u16);

    memcpy(&u32, buffer+2, 4);

    packet.length = ntohl(u32);

}



void PacketHandler::SerializeHelloWorldPacket(HelloWorldPacket packet, char buffer[])

{

    uint16_t u16;



    u16 = htons(packet.byteOrder);

    memcpy(buffer+0, &u16, 2);

    memcpy(buffer+2, &packet.content, sizeof packet.content);

}



void PacketHandler::UnserializeHelloWorldPacket(char buffer[], HelloWorldPacket &packet)

{

    uint16_t u16;



    memcpy(&u16, buffer+0, 2);

    packet.byteOrder = ntohs(u16);



    strcpy(packet.content, buffer+2);



}

И вот как я отправляю данные на сервер:

int EventHandler::SendHelloWorld(int fd)

{

    HeaderPacket hp;

    HelloWorldPacket hc;

    char buffer[256];

    int sendResult;

    char message[] = "hello_first_message\r\n";





    hp.opcode = HELLOWORLD;

    hp.length = sizeof message;

    memcpy(hc.content, message, sizeof message);





    packets->SerializeHeaderPacket(hp, buffer);

    packets->SerializeHelloWorldPacket(hc, buffer+6);



    sendResult = write(fd, buffer, sizeof buffer);







    return sendResult;



}

Спасибо за вашу помощь.

1 Ответ

0 голосов
/ 25 января 2012

Я нашел проблему. Когда я писал на сервер, я использовал размер буфера , а размер буфера был 256, а я не читал 256 байтов.

Спасибо за вашу помощь.

...