一个发送窗口已满、接收窗口为空的套接字,收到TCP RST后(未收到TCP FIN),将触发POLLIN、POLLOUT、POLLRDHUP、POLLHUP、POLLERR事件。
相关代码:
#include <cassert>
#include <cstdio>
#include <siren/ip_endpoint.h>
#include <siren/loop.h>
#include <siren/stream.h>
#include <siren/tcp_socket.h>
using namespace siren;
int
main()
{
Loop l(16 * 1024);
l.createFiber([&] () -> void {
TCPSocket ss(&l);
ss.setReuseAddress(true);
ss.listen(IPEndpoint(0, 0));
IPEndpoint ipe = ss.getLocalEndpoint();
Event e = l.makeEvent();
l.createFiber([&] () -> void {
/* mark */ std::puts("step 2");
TCPSocket cs(&l);
cs.connect(ipe);
e.waitFor();
/* mark */ std::puts("step 5");
cs.setNoDelay(true);
// 接收窗口还有数据未读出,cs析构时调用close()将向对端发送TCP RST
/* mark */ std::puts("step 6");
});
/* mark */ std::puts("step 1");
TCPSocket cs = ss.accept();
/* mark */ std::puts("step 3");
e.trigger();
cs.setNoDelay(true);
char d[4096];
while (l.send(cs.getFD(), d, sizeof(d), MSG_DONTWAIT) >= 0); // 写满
/* mark */ std::puts("step 4");
l.usleep(1000000);
/* mark */ std::puts("step 7");
pollfd pfd;
pfd.fd = cs.getFD();
pfd.events = POLLIN | POLLOUT | POLLRDHUP;
assert(l.poll(&pfd, 1, -1) == 1);
assert((pfd.revents & POLLIN) != 0);
assert((pfd.revents & POLLOUT) != 0);
assert((pfd.revents & POLLRDHUP) != 0);
assert((pfd.revents & POLLPRI) == 0);
assert((pfd.revents & POLLHUP) != 0);
assert((pfd.revents & POLLERR) != 0);
/* mark */ std::puts("step 8");
});
l.run();
return 0;
}
编译运行:
# g++ -std=c++14 test.cc -lsiren -lpthread && ./a.out
step 1
step 2
step 3
step 4
step 5
step 6
step 7
step 8