данные TCP изменены после передачи через сокет - PullRequest
0 голосов
/ 01 октября 2019

Я пишу программу для передачи данных между двумя машинами с сокетом tcp / ip на C / C ++. Программы проверяют размер каждого чтения и записи, чтобы убедиться в правильности размера передаваемых данных. Я также реализую проверку контрольной суммы, чтобы убедиться, что переданы правильные данные. Большую часть времени нет проблем. Время от времени, например, раз в 50 000 раз, я замечаю, что полученные данные имеют ту же длину, что и отправляющая сторона, но часть их содержимого была изменена. Измененная часть всегда имеет длину 64 байта. Ниже мой код отправить и прочитать. Пожалуйста, помогите мне понять, как это может произойти и как это предотвратить. Спасибо!

bool WriteSocket(int pSocket, unsigned char* pData, uint32_t pNumBytes, uint32_t &pNumBytesWritten, uint32_t &pNumWrites)
{
    int rc;
    unsigned char* currPos = pData;
    uint32_t numFailures = 0;

    pNumBytesWritten = 0;
    pNumWrites = 0;
    while ( true )
    {
        rc = write(pSocket, currPos, pNumBytes);
        pNumWrites++;
        if ( rc < 0 )
        {
            if ( errno == EINTR )
                continue;
            numFailures++;
            if ( numFailures >= 5 )
                break;
            else
                continue;
        }
        pNumBytesWritten += rc;
        if ( rc == pNumBytes )
            return true;
        pNumBytes -= rc;
        currPos += rc;
        numFailures = 0;
    };
    return false;
};

bool ReadSocket(int pSocket, unsigned char* pData, uint32_t pNumBytes)
{
    int rc;
    unsigned char* currPos = pData;
    uint32_t numFailures = 0;

    while ( true )
    {
        rc = read(pSocket, currPos, pNumBytes);
        if ( rc < 0 )
        {
            if ( errno == EINTR )
                continue;
            numFailures++;
            if ( numFailures >= 5 )
                break;
            else
                continue;
        }
        if ( rc == pNumBytes )
            return true;
        pNumBytes -= rc;
        currPos += rc;
        numFailures = 0;
    }; 
    return false;
};

1 Ответ

0 голосов
/ 02 октября 2019

Если чтение / запись сокета завершается неудачей по любой причине, кроме EINTR или EAGAIN / EWOULDBLOCK, вы должны рассматривать это как фатальную ошибку. Не повторяйте операцию, просто остановите и закройте розетку. Но ваш код этого не делает, он пытается повторить неудачную операцию.

Кроме того, при чтении вы не обрабатываете случай, когда чтение возвращает 0, когда узел отключается изящно . В этом случае ошибка сокета не сообщается.

Вместо этого попробуйте что-то вроде этого:

bool WriteSocket(int pSocket, unsigned char* pData, uint32_t pNumBytes, uint32_t &pNumBytesWritten, uint32_t &pNumWrites)
{
    int rc;
    uint32_t numRetries = 0;

    pNumBytesWritten = 0;
    pNumWrites = 0;

    while ( pNumBytes > 0 )
    {
        rc = write(pSocket, pData, pNumBytes);
        if ( rc < 0 )
        {
            if ( errno == EINTR )
                continue;

            if ( (errno == EAGAIN) || (errno == EWOULDBLOCK) )
            {
                ++numRetries;
                if ( numRetries < 5 )
                {
                    // TODO: use select() or epoll() w/ timeout to
                    // detect when then socket is writable again...
                    continue;
                }
            }

            return false;
        }

        ++pNumWrites;
        pNumBytesWritten += rc;
        pNumBytes -= rc;
        pData += rc;

        numRetries = 0;
    }

    return true;
}

bool ReadSocket(int pSocket, unsigned char* pData, uint32_t pNumBytes)
{
    int rc;
    uint32_t numRetries = 0;

    while ( pNumBytes > 0 )
    {
        rc = read(pSocket, pData, pNumBytes);
        if ( rc < 0 )
        {
            if ( errno == EINTR )
                continue;

            if ( (errno == EAGAIN) || (errno == EWOULDBLOCK) )
            {
                ++numRetries;
                if ( numRetries < 5 )
                {
                    // TODO: use select() or epoll() w/ timeout to
                    // detect when then socket is readable again...
                    continue;
                }
            }

            return false;
        }
        else if ( rc == 0 )
        {
            return false;
        }
        else
        {
            pNumBytes -= rc;
            pData += rc;

            numRetries = 0;
        }
    }

    return true;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...