在不使用getline

时间:2017-04-14 20:17:04

标签: c++ boost boost-asio

我正在尝试转换程序(它是vscode和调试之间的桥梁) 该程序是用C#编写的。

它基于o vscode-mono-debug

https://github.com/Microsoft/vscode-mono-debug/blob/master/src/Protocol.cs

那么, 在C#中,我可以将标准输入读作流:

 byte[] buffer = new byte[BUFFER_SIZE];
Stream inputStream = Console.OpenStandardInput();
    _rawData = new ByteBuffer();

        while (!_stopRequested) {
            var read = await inputStream.ReadAsync(buffer, 0, buffer.Length);

            if (read == 0) {
                // end of stream
                break;
            }

            if (read > 0) {
                _rawData.Append(buffer, read);
                ProcessData();
            }
        }

我试试这个:

#define _WIN32_WINNT 0x05017
#define BUFFER_SIZE 4096
#include<iostream>
#include<thread>
#include <sstream>

using namespace std;
class ProtocolServer
{

    private:
        bool _stopRequested;
        ostringstream _rawData;
    public:
        void Start()
        {

            char buffer[BUFFER_SIZE];

            while (!cin.eof())
            {

                cin.getline(buffer,BUFFER_SIZE);

                if (cin.fail())
                {
                    //error
                    break;
                }
                else
                {
                    _rawData << buffer;
                }

            }
        }

};

int main()
{
    ProtocolServer *server = new ProtocolServer();
    server->Start();
    return 0;

}

输入:

Content-Length: 261\r\n\r\n{\"command\":\"initialize\",\"arguments\":{\"clientID\":\"vscode\",\"adapterID\":\"advpl\",\"pathFormat\":\"path\",\"linesStartAt1\":true,\"columnsStartAt1\":true,\"supportsVariableType\":true,\"supportsVariablePaging\":true,\"supportsRunInTerminalRequest\":true},\"type\":\"request\",\"seq\":1}

这正确读取前两行。由于协议没有放在最后,它在3次交互中卡在cin.getline中。

切换到read()会使它在cin.read()处停留,并且根本不会读取任何内容。

我发现了一些类似的问题: StackOverFlow Question

示例: Posix_chat_client

但我不需要它必须是异步的,但它适用于Windows和Linux。

对不起我的英文

谢谢!

1 个答案:

答案 0 :(得分:4)

您想要的是无格式输入操作

这是使用std :: iostream的1:1翻译。唯一的“技巧”是使用和尊重gcount()

std::vector<char> buffer(BUFFER_SIZE);
auto& inputStream = std::cin;
_rawData = std::string {}; // or _rawData.clear(), e.g.

while (!_stopRequested) {
    inputStream.read(buffer.data(), buffer.size());
    auto read = inputStream.gcount();

    if (read == 0) {
        // end of stream
        break;
    }

    if (read > 0) {
        _rawData.append(buffer.begin(), buffer.begin() + read);
        ProcessData();
    }
}

我个人建议放弃read == 0检查以支持更准确:

if (inputStream.eof()) { break; }   // end of stream
if (!inputStream.good()) { break; } // failure

请注意,!good()也会抓住eof(),因此您可以

if (!inputStream.good()) { break; } // failure or end of stream

现场演示

<强> Live On Coliru

#include <iostream>
#include <vector>
#include <atomic>

struct Foo {

    void bar() {
        std::vector<char> buffer(BUFFER_SIZE);
        auto& inputStream = std::cin;
        _rawData = std::string {};

        while (!_stopRequested) {
            inputStream.read(buffer.data(), buffer.size());
            auto read = inputStream.gcount();

            if (read > 0) {
                _rawData.append(buffer.begin(), buffer.begin() + read);
                ProcessData();
            }

            if (!inputStream.good()) { break; } // failure or end of stream
        }
    }
  protected:
    void ProcessData() {
        //std::cout << "got " << _rawData.size() << " bytes: \n-----\n" << _rawData << "\n-----\n";
        std::cout << "got " << _rawData.size() << " bytes\n";
        _rawData.clear();
    }

    static constexpr size_t BUFFER_SIZE = 128;
    std::atomic_bool _stopRequested { false };
    std::string _rawData;
};

int main() {
    Foo foo;
    foo.bar();
}

打印(例如,在阅读自己的源文件时):

got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 128 bytes
got 92 bytes