Linux下如何重現Connection reset by peer、Broken pipe錯誤(1)

設置套接字選項SO_LINGER爲(on, 0)後關閉套接字,將當即向對端發送TCP RST。c++

對端接收TCP RST後:socket

  1. 進行讀操做:tcp

    1. 若已接收TCP FIN,返回0。
    2. 若未接收TCP FIN,返回錯誤「Connection reset by peer」。
  2. 進行寫操做
    1. 若已接收TCP FIN,返回錯誤「Broken pipe」。
    2. 若未接收TCP FIN,返回錯誤「Connection reset by peer」。

下面用代碼進行驗證(使用SIren庫)。oop

狀況1.1

#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.closeWrite(); // 發送TCP FIN
            cs.setLinger(true, 0); // 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);
        /* mark */ std::puts("step 4");
        l.usleep(1000000); // 接收對端發送的TCP FIN和TCP RST
        /* mark */ std::puts("step 7");
        Stream s;
        s.reserveBuffer(1);
        assert(cs.read(&s) == 0);  // 無異常,無數據
        /* mark */ std::puts("step 8");
    });

    l.run();
    return 0;
}

編譯運行spa

# 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

狀況1.2

#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.setLinger(true, 0); // 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);
        /* mark */ std::puts("step 4");
        l.usleep(1000000); // 接收對端發送的TCP RST
        /* mark */ std::puts("step 7");
        Stream s;
        s.reserveBuffer(1);
        cs.read(&s);  // 拋出異常
        /* mark */ std::puts("step 8");
    });

    l.run();
    return 0;
}

編譯運行code

# g++ -std=c++14 test.cc -lsiren -lpthread && ./a.out
step 1
step 2
step 3
step 4
step 5
step 6
step 7
terminate called after throwing an instance of 'std::system_error'
  what():  read() failed: Connection reset by peer
Aborted

狀況2.1

#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.closeWrite(); // 發送TCP FIN
            cs.setLinger(true, 0); // 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);
        /* mark */ std::puts("step 4");
        l.usleep(1000000); // 接收對端發送的TCP FIN和TCP RST
        /* mark */ std::puts("step 7");
        Stream s;
        s.write("a", 1);
        cs.write(&s);  // 拋出異常
        /* mark */ std::puts("step 8");
    });

    l.run();
    return 0;
}

編譯運行ip

# g++ -std=c++14 test.cc -lsiren -lpthread && ./a.out
step 1
step 2
step 3
step 4
step 5
step 6
step 7
terminate called after throwing an instance of 'std::system_error'
  what():  send() failed: Broken pipe
Aborted

狀況2.2

#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.setLinger(true, 0); // 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);
        /* mark */ std::puts("step 4");
        l.usleep(1000000); // 接收對端發送的TCP RST
        /* mark */ std::puts("step 7");
        Stream s;
        s.write("a", 1);
        cs.write(&s);  // 拋出異常
        /* mark */ std::puts("step 8");
    });

    l.run();
    return 0;
}

編譯運行get

# g++ -std=c++14 test.cc -lsiren -lpthread && ./a.out
step 1
step 2
step 3
step 4
step 5
step 6
step 7
terminate called after throwing an instance of 'std::system_error'
  what():  send() failed: Connection reset by peer
Aborted
相關文章
相關標籤/搜索