Ошибка при разборе строки и попытке найти символ '\ 0' - PullRequest
0 голосов
/ 18 ноября 2009

Я пытаюсь заставить одну сторону отправить сообщение об ошибке клиенту, но клиент не может правильно его проанализировать.

Моя ошибка >>>>> в моей функции parseString, она позволяет index = 0, и поэтому я получаю выход за пределы диапазона для моего вызова substr.

Сторона сервера :::

   #define ERRBUFSIZE 51

    string error = "Error - Already Registered: ";
                error.append(name);
                char err[ERRBUFSIZE];
                err[0] = 0;
                std::copy(error.begin(), error.end(), err+1);

                err[error.size() + 2] = '\0';

                if (send(sock, &err, ERRBUFSIZE, 0) < 0)
                {
                DieWithError("send() failed");
                }

Клиентская сторона (кто получает) ::

   char msgBuffer[ERRBUFSIZE];
        int bytesRcvd = 0;
        int totalRcvd = 0;
        while(totalRcvd != ERRBUFSIZE)
        {   
            // Get Message from Server
            if ((bytesRcvd = recv(sock, msgBuffer, ERRBUFSIZE, 0)) < 0)
            DieWithError("recv() failed or connection closed prematurely");

            totalRcvd += bytesRcvd; 
        }

        cout << "Bytes received: " << totalRcvd << endl;
        msgBuffer[totalRcvd] = '\0';

        string rcvMsg( msgBuffer , msgBuffer + totalRcvd);
        cout << rcvMsg << endl;
        rcvMsg = parseString(rcvMsg);

        return rcvMsg;

где ....

   string TCPClient::parseString(string message)
    {
        cout << "parsing new string" << endl;
        int index = message.find('\0');
        string result = message.substr(0, index);
        cout << "THE RESULT :: " << result << endl;
        return result;
    }

Ответы [ 4 ]

0 голосов
/ 18 ноября 2009

Во-первых, протокол противный. Вы отправляете блоки фиксированного размера, когда хотите отправить строку с нулевым символом в конце ... было бы проще просто указать длину строки в начале сообщения.

Во-вторых, вы не правильно читаете из сокета, это просто работает, если у вас нет других сообщений в конвейере. Если ваш цикл while был действительно использован, вы перезаписали бы первый фрагмент при любых последующих чтениях.

В любом случае, непосредственной причиной ошибки является то, что вы добавляете к строке нулевой терминатор (разделитель?). Разве это не объясняет, почему вы всегда находите свой nul по индексу 0? Если вы не видите его, попробуйте выписать содержимое буфера как отправленное.

#define ERRBUFSIZE 51

void server(string const &name)
{
    string error = "Error - Already Registered: ";
    error.append(name);
    char err[ERRBUFSIZE];
    // you sure you want a NUL terminator at index 0??
    err[0] = 0;
    // can replace both lines with strcpy(err, error.c_str())
    std::copy(error.begin(), error.end(), err+1);
    err[error.size() + 2] = '\0';

    if (send(sock, &err, ERRBUFSIZE, 0) < 0)
        DieWithError("send() failed");
}

string parseString(string const &message) // no need to copy
{
    // ... this is redundant anyway, see below
}

string client()
{
    char msgBuffer[ERRBUFSIZE];
    int bytesRcvd = 0;
    int totalRcvd = 0;
    while(totalRcvd != ERRBUFSIZE)
    {       
        // Get Message from Server
        // ... recv(sock, msgBuffer+totalRcvd, ERRBUFSIZE-totalRcvd) ...
        if ((bytesRcvd = recv(sock, msgBuffer, ERRBUFSIZE, 0)) < 0)
            DieWithError("recv() failed or connection closed prematurely");

        totalRcvd += bytesRcvd; 
    }

    cout << "Bytes received: " << totalRcvd << endl;
    //sizeof(msgBuffer)==ERRBUFSIZE==totalRcvd, so this overflows
    msgBuffer[totalRcvd] = '\0';

    // assuming you skip the leading \0, msgBuffer is already nul-terminated
    // so use string rcvMsg(msgBuffer) and skip the parseString/substr
    string rcvMsg( msgBuffer , msgBuffer + totalRcvd);
    cout << rcvMsg << endl;
    // rcvMsg = parseString(rcvMsg);

    return rcvMsg;
}
0 голосов
/ 18 ноября 2009

Из (очень сложного для чтения) кода я думаю, что вы можете столкнуться с "адским индексированием".

Убедитесь, что totalRecvd на самом деле является индексом, в который вы хотите записать \0, и что, когда вы создаете rcvMsg, вы добавляете к нему индекс \0 (msgBuffer + totalRcvd выглядит как собачка, когда вы ' мы помещаем ваш маркер конца строки в байт totalRcvd, обычно вы получаете строку между (start, end-1) индексами, которые вы пишете).

Также - поиск \0 не имеет смысла, так как это всего лишь маркер.

Также (2) - если totalRcvd == ERRBUFSIZE вы не можете получить доступ к msgBuffer [totalRcvd], у вас есть доступ только к индексам в диапазоне (0, ERRBUFSIZE -1)

0 голосов
/ 18 ноября 2009

Используйте std :: vector вместо std :: string, если вы хотите управлять буферами. '\ 0' и std :: basic_string плохо сочетаются.

0 голосов
/ 18 ноября 2009

Почему бы не изменить вашу parseString на следующую:

string TCPClient::parseString(const string& message, int strLength )
{
    cout << "parsing new string" << endl;
    string result = message.substr( 0, strLength );
    cout << "THE RESULT :: " << result << endl;
    return result;
}

А затем измените код вызова на:

rcvMsg = parseString(rcvMsg, totalRcvd );

В противном случае вы даже можете использовать функцию string (size ()).

Редактировать: Стоит также отметить, что поиск будет продвигаться по строке, пока не будет найден символ '\ 0', но на самом деле не будет его искать. Кажется немного странным план поместить строку в строковый объект (который хранит длину), а затем попытаться самостоятельно вычислить длину с помощью медленного итеративного процесса.

Edit2: если вы просто хотите сделать это с массивом символов, вы можете выполнить ручной поиск следующим образом.

int index = 0;
while( *charString++ != '\0' ) index++;

Это так просто:)

...