解析字符串并尝试查找'\ 0'字符时出错

时间:2009-11-18 08:48:51

标签: c++ networking sockets

我试图让一方向客户端发送错误消息,但客户端无法正确解析它。

我的错误是>>>>>在我的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 :(得分:0)

为什么不将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 );

如果没有,你甚至可以使用字符串的“size()”函数。

编辑:还值得注意的是,find会在字符串中前进,直到找到'\ 0'字符,但实际上并不会查找它。将字符串放入字符串对象(存储长度)然后尝试通过缓慢的迭代过程自己计算长度似乎有点奇怪。

Edit2:如果您只想使用字符数组,可以按如下方式进行手动搜索。

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

就这么简单:)

答案 1 :(得分:0)

从(非常难以阅读)的代码中,我认为你可能会遇到“索引地狱”。

检查totalRecvd实际上是您要编写\0的索引,并在创建rcvMsg时向其添加\0索引(当你将字符串结束标记放在msgBuffer + totalRcvd字节上时,totalRcvd看起来很小便,通常你会在你写的(start,end-1)索引之间得到一个字符串。

另外 - 搜索\0毫无意义,因为这只是一个标记。

另外(2) - 如果totalRcvd == ERRBUFSIZE您无法访问msgBuffer [totalRcvd],则只能访问范围(0, ERRBUFSIZE -1)

中的索引

答案 2 :(得分:0)

当您想要管理缓冲区时,请使用std :: vector而不是std :: string。 '\ 0'和std :: basic_string组合得不好。

答案 3 :(得分:0)

首先,协议是令人讨厌的。当你想发送一个以空字符结尾的字符串时,你正在发送固定大小的块...只是将字符串长度放在消息的前面会更简单。

其次,你没有正确地从套接字中读取,只要你在管道中没有任何其他消息,它就会正常工作。 如果你的while循环真的被运用了,你就会用随后的任何读取覆盖第一个片段。

无论如何,这个bug的最直接原因是你在字符串前面添加了一个nul终止符(separator?)。这不能解释为什么你总是在索引0找到你的nul? 如果您看不到它,请尝试写出已发送的缓冲区内容。

#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;
}