1

我正在Cap'n Proto的优秀kj-async 库上实现一个网络应用程序。

argv[1]下面的示例代码通过 TCP提供一个(大的、预加载的)文件 ( )。如果我将它直接重定向到带有nc localhost 9004 > test的文件,则可以正确检索该文件。

如果我让文件输出到终端而不重定向到文件,我会看到间歇性损坏。我怀疑当终端无法足够快地写入输出时,底层调用::write失败EAGAIN,并且下一次调用以某种方式使用了不正确的偏移量。EWOULDBLOCK当我尝试通过 wifi 获取它时,这更可靠地重现。

我认为我必须对对象生命周期有一些问题,但是 valgrind 没有任何提示。

我使用了 angular.min.js但任何不太小的文件都为我重现了这个问题

我在 64 位 Linux 4.1.6 (Arch) 上使用来自 git 的 libkj

#include <fstream>
#include <string>
#include <kj/async-io.h>

class Server : public kj::TaskSet::ErrorHandler {
public:
    Server(const char* filename) :
        tasks(*this),
        ctx(kj::setupAsyncIo())
    {
        std::ifstream fstr(filename);
        fstr.seekg(0, std::ios::end);
        size_t sz = fstr.tellg();
        if(fstr.rdstate() == 0) {
            large.resize(sz);
            fstr.seekg(0);
            fstr.read(&large[0], sz);
        }
    }
    void taskFailed(kj::Exception&& exception) override {}
    void run() {
        tasks.add(ctx.provider->getNetwork().parseAddress("*:9004", 0)
               .then([&](kj::Own<kj::NetworkAddress>&& addr) {
            auto listener = addr->listen();
            accept(kj::mv(listener));
        }));
        kj::NEVER_DONE.wait(ctx.waitScope);
    }
private:
    void accept(kj::Own<kj::ConnectionReceiver>&& listener) {
        auto ptr = listener.get();
        tasks.add(ptr->accept().then(kj::mvCapture(kj::mv(listener),
           [&](kj::Own<kj::ConnectionReceiver>&& listener,
                kj::Own<kj::AsyncIoStream>&& cn) {
            accept(kj::mv(listener));
            tasks.add(cn->write(large.c_str(), large.size()).attach(kj::mv(cn)));
        })));
    }

private:    
    kj::TaskSet tasks;
    kj::AsyncIoContext ctx;
    std::string large;
};


int main(int argc, char** argv) {
    Server s(argv[1]);
    s.run();
}

编译并运行:

g++ -std=c++11 test.cpp -lkj-async -lkj -o test
./test path/to/angular.min.js

要求:

nc localhost 9004
4

0 回答 0