我正在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