为什么我的缓冲区在多次读取()后会保存相同的数据

Why is my buffer hold the same data after multiple read()s?

本文关键字:保存 数据 缓冲区 我的 读取 为什么      更新时间:2023-10-16

我有一个使用命名管道的C语言的客户端/服务器程序。我的服务器应该发送消息"last line",让客户端知道最后一行即将到来,因为这一行必须专门输出。我的客户端读取"最后一行",然后应该得到最后一行的实际内容,但在下一个read()之后,我的缓冲区仍然保存"最后一行将"。

编辑根据请求,这里是进行读/写的服务器和客户端代码。我的程序的总体目标是向服务器发送一个文件名和搜索词,服务器逐行读取文件,并返回在每行中找到该词的频率。然后由客户打印该信息。在读取整个文件后,服务器将发送一个总额,客户端将打印出特殊格式的总额。服务器结束"服务器EOF",表示已完成通信。这是硬件分配,所以这些是我给出的规范。

服务器:

 ifstream rf(requestedFileName)
        size_t found;
        getline(rf,tempLine);//gets the first line of the file
        while (!rf.eof())
        {       
                currentLineNumber++;
                found= tempLine.find(requestedTarget);//searches line for target
                while(found != string::npos)//if it was found, increase counts and search again
                {
                        totalTimesFoundInFile++;
                        totalTimesFoundOnLine++;
                        found=tempLine.find(requestedTarget, found+1);
                }
 if(totalTimesFoundOnLine != 0) //If it was found create the right string and send it to client
                {
                        int n = sprintf(stringToSend, "Appeared on Line %d,     %d times",currentLineNumber,
                                        totalTimesFoundOnLine);
                        write(fd2, stringToSend, sizeof(stringToSend));
                }
                getline(rf,tempLine);//gets the next line
                totalTimesFoundOnLine = 0; //resets the found count
        }
        //create the special total string. 
        int t = sprintf(stringToSend, "Appeared a Total of %d Times",totalTimesFoundInFile);
        //Send a message to the client to let it know the special total line is coming
        char finalLine[] = "final line";
        if(write(fd2, finalLine, sizeof(finalLine)) != sizeof(finalLine))
        {
                cout<<"error writing" <<endl; }
        cout <<"Just put 'finalLine' into pipe" <<endl;//lets me know the signal went out
        int s= write(fd2,stringToSend, t);//writes the special total line into the pipe
        if(s != t)
                cout <<"error writing" <<endl;
        cout <<"Just put last line into pipe" <<endl;//verifies that the special line got into the pipe and didn't block
        char endingMessage[]="Server-EOF";//Let the client know the server is finished
        write(fd2, endingMessage, sizeof(endingMessage));
        cout <<"Wrote endingMessage" <<endl; //verifies the message got sent

客户:

char endMessage[] = "Server-EOF";
int nread;
nread = read(fd2, buffer, maxBufferSize);//reads the first input from the pipe
if(nread == -1) cout << "a read error occurred" <<endl;
else{
        while(strcmp(buffer, endMessage) != 0)  //check to 'server-EOF' message
        {
                cout << "Size of buffer is: " << strlen(buffer) <<endl;//verifies size of message recieved
                if(strcmp(buffer, "final line") == 0)
                {//Handler to recieve special total message and output it
                        nread =read(fd2, buffer, maxBufferSize);//get total message
                        if(nread == -1)
                        {
                                cout <<"a read error occurred" <<endl;
                                break;
                        }
                        else{
                                cout <<"Size of buffer is: " <<strlen(buffer) <<endl;//verify it got the total message
                                cout<< "Client : PID" << clientPID << " - Target >>"
                                        << requestedTarget <<"<< in File >>" << requestedFileName
                                        <<"<< " << buffer << endl;
                                }
                }
                else{//Print out the information about search numbers for regular liens
                        cout <<"Client : PID " << clientPID << " - Target >>"
                                <<requestedTarget <<"<< " << buffer <<endl;
                    }
                nread=read(fd2, buffer, maxBufferSize);//reads next message from pipe
                if(nread == -1)
 {
                        cout << "a read error occurred" << endl;
                        break;
                }
        }
        }

输出:

Final string to send: Appeared a Total of 4 Times
Just put 'finalLine' into pipe
Just put last line into pipe
Wrote endingMessage
Size of buffer is: 27
Client : PID 5172 - Target >>apple<< Appeared on Line 1,       1 times
Size of buffer is: 27
Client : PID 5172 - Target >>apple<< Appeared on Line 2,       1 times
Size of buffer is: 27
Client : PID 5172 - Target >>apple<< Appeared on Line 4,       2 times
Size of buffer is: 10
Size of buffer is: 10
Client : PID6144 - Target >>apple<< in File >>pipedTest.txt<< final line
//This line ^^ should say something like" appeared a total of 11 times" instead of "final line"

我的客户端似乎收到了消息"最后一行"(10个字符),但当它应该读取之后的总行时,它显然在缓冲区中只有"最后一行将"。我知道这一点,因为后面的输出只是一个以"最后一行"作为缓冲区的无休止循环。该循环一定意味着我所有进一步的read()调用都返回了一个缓冲区,其中包含"最后一行"

管道是一个字节流。你无法改变这一点。您需要修复客户端才能正确查找消息的结尾。如果您有一个字节流,但需要一个消息流,那么您需要实现一个消息层。

这里有一些坏代码:

nread = read(fd2, buffer, maxBufferSize);//reads the first input from the pipe
if(nread == -1) cout << "a read error occurred" <<endl;
else{
        while(strcmp(buffer, endMessage) != 0)  //check to 'server-EOF' message

strcmp函数仅适用于C样式字符串,不适用于任意数据。nread变量保存您读取的数据的长度,但您完全忽略它来处理数据。这不可能奏效。

数据保证有序,但即使是短消息也可能以块的形式到达。如果你想要新鲜的话,你可以试着关闭管道,然后打开一个新的。或者,您可以添加某种终止来指示每次传输的结束。接收信息的代码必须将传入数据添加到缓冲区,然后才能找到结束(这可以指示下一条消息的开始)。