亚洲精品永久视频_久久精品视频16_亚洲精品永久视频_日韩黄色片在线_五月天综合婷婷_懂色av一区二区三区四区五区_www.这里只有精品_国产成人久久婷婷精品流白浆_久久久九九九热_国产一区亚洲二区三区_日韩中字在线观看_男女猛烈激情xx00免费视频

您的位置:首頁>熱點 >
  • CS144 計算機網絡 Lab4:TCP Connection

    2023-05-06 20:27:45 來源: 博客園
前言

經過前面幾個實驗的鋪墊,終于到了將他們組合起來的時候了。Lab4 將實現 TCP Connection 功能,內部含有 TCPReceiverTCPSender,可以與 TCP 連接的另一個端點進行數據交換。


(資料圖)

實驗要求

簡單來說,這次實驗就是要在 TCPConnection類中實現下圖所示的有限狀態機:

這些狀態對應 TCPState的內部枚舉類 State

//! \brief Official state names from the [TCP](\ref rfc::rfc793) specificationenum class State {    LISTEN = 0,   //!< Listening for a peer to connect    SYN_RCVD,     //!< Got the peer"s SYN    SYN_SENT,     //!< Sent a SYN to initiate a connection    ESTABLISHED,  //!< Three-way handshake complete    CLOSE_WAIT,   //!< Remote side has sent a FIN, connection is half-open    LAST_ACK,     //!< Local side sent a FIN from CLOSE_WAIT, waiting for ACK    FIN_WAIT_1,   //!< Sent a FIN to the remote side, not yet ACK"d    FIN_WAIT_2,   //!< Received an ACK for previously-sent FIN    CLOSING,      //!< Received a FIN just after we sent one    TIME_WAIT,    //!< Both sides have sent FIN and ACK"d, waiting for 2 MSL    CLOSED,       //!< A connection that has terminated normally    RESET,        //!< A connection that terminated abnormally};

除了三次握手和四次揮手外,我們還得處理報文段首部 RST標志被置位的情況,這時候應該將斷開連接,并將內部的輸入流和輸入流標記為 error,此時的 TCPState應該是 RESET

代碼實現

先在類聲明里面加上一些成員:

class TCPConnection {  private:    TCPConfig _cfg;    TCPReceiver _receiver{_cfg.recv_capacity};    TCPSender _sender{_cfg.send_capacity, _cfg.rt_timeout, _cfg.fixed_isn};    //! outbound queue of segments that the TCPConnection wants sent    std::queue _segments_out{};    //! Should the TCPConnection stay active (and keep ACKing)    //! for 10 * _cfg.rt_timeout milliseconds after both streams have ended,    //! in case the remote TCPConnection doesn"t know we"ve received its whole stream?    bool _linger_after_streams_finish{true};    bool _is_active{true};    size_t _last_segment_time{0};    /**     * @brief 發送報文段     * @param fill_window 是否填滿發送窗口    */    void send_segments(bool fill_window = false);    // 發送 RST 報文段    void send_rst_segment();    // 中止連接    void abort();  public:    // 省略其余成員}

接著實現幾個最簡單的成員函數:

size_t TCPConnection::remaining_outbound_capacity() const { return _sender.stream_in().remaining_capacity(); }size_t TCPConnection::bytes_in_flight() const { return _sender.bytes_in_flight(); }size_t TCPConnection::unassembled_bytes() const { return _receiver.unassembled_bytes(); }size_t TCPConnection::time_since_last_segment_received() const { return _last_segment_time; }bool TCPConnection::active() const { return _is_active; }
主動連接

客戶端可以調用 TCPConnection::connect函數發送 SYN報文段請求與服務端建立連接,由于 Lab3 中實現的 TCPSender::fill_window()函數會根據發送方的狀態選擇要發送的報文段類型,在還沒建立連接的情況下,這里直接調用 fill_window()就會將一個 SYN報文段放在隊列中,我們只需將其取出放到 TCPConnection_segments_out隊列中即可:

void TCPConnection::connect() {    // 發送 SYN    send_segments(true);}void TCPConnection::send_segments(bool fill_window) {    if (fill_window)        _sender.fill_window();    auto &segments = _sender.segments_out();    while (!segments.empty()) {        auto seg = segments.front();        // 設置 ACK、確認應答號和接收窗口大小        if (_receiver.ackno()) {            seg.header().ackno = _receiver.ackno().value();            seg.header().win = _receiver.window_size();            seg.header().ack = true;        }        _segments_out.push(seg);        segments.pop();    }}
主動關閉

當上層程序沒有更多數據需要發送時,將會調用 TCPConnection::end_input_stream()結束輸入,這時候需要發送 FIN報文段給服務端,告訴他自己沒有更多數據要發送了,但是可以繼續接收服務端發來的數據。客戶端的狀態由 ESTABLISHED轉移到 FIN_WAIT_1,服務端收到 FIN之后變成 CLOSE_WAIT狀態,并回復 ACK給客戶端,客戶端收到之后接著轉移到 FIN_WAIT_2狀態。

如果服務端數據傳輸完成了,會發送 FIN報文段給客戶端,轉移到 LAST_ACK狀態,此時客戶端會回復最后一個 ACK給服務端并進入 TIME_WAIT超時等待狀態,如果這個等待時間內沒有收到服務端重傳的 FIN,就說明 ACK順利到達了服務端且服務端已經變成 CLOSED狀態了,此時客戶端也能斷開連接變成 CLOSED了。

void TCPConnection::end_input_stream() {    // 發送 FIN    _sender.stream_in().end_input();    send_segments(true);}

在上述情景中,客戶端是主動關閉(Active Close)的一方,服務端是被動關閉(Passive Close)的一方。

主動重置連接

有兩種情況會導致發送 RST報文段來主動重置連接:

TCPSender超時重傳的次數過多時,表明通信鏈路存在故障;TCPConnect對象被釋放但是 TCP 仍然處于連接狀態的時候;

和 Lab3 中類似,TCPConnection通過外部定期調用 tick()函數來得知過了多長時間,在 tick()函數里還得處理超時等待的情況:

//! \param[in] ms_since_last_tick number of milliseconds since the last call to this methodvoid TCPConnection::tick(const size_t ms_since_last_tick) {    _sender.tick(ms_since_last_tick);    // 重傳次數太多時需要斷開連接    if (_sender.consecutive_retransmissions() > _cfg.MAX_RETX_ATTEMPTS) {        return send_rst_segment();    }    // 重傳數據包    send_segments();    _last_segment_time += ms_since_last_tick;    //  TIME_WAIT 超時等待狀態轉移到 CLOSED 狀態    if (TCPState::state_summary(_receiver) == TCPReceiverStateSummary::FIN_RECV &&        TCPState::state_summary(_sender) == TCPSenderStateSummary::FIN_ACKED &&        _last_segment_time >= 10 * _cfg.rt_timeout) {        _linger_after_streams_finish = false;        _is_active = false;    }}TCPConnection::~TCPConnection() {    try {        if (active()) {            cerr << "Warning: Unclean shutdown of TCPConnection\n";            // Your code here: need to send a RST segment to the peer            send_rst_segment();        }    } catch (const exception &e) {        std::cerr << "Exception destructing TCP FSM: " << e.what() << std::endl;    }}void TCPConnection::send_rst_segment() {    abort();    TCPSegment seg;    seg.header().rst = true;    _segments_out.push(seg);}void TCPConnection::abort() {    _is_active = false;    _sender.stream_in().set_error();    _receiver.stream_out().set_error();}
接收報文段

外部通過 TCPConnection::segment_received()將接收到的報文段傳給它,在這個函數內部,需要將確認應答號和接收窗口大小告訴 TCPSender,好讓他接著填滿發送窗口。接著還需要把報文段傳給 TCPReceiver來重組數據,并更新確認應答號和自己的接收窗口大小。然后 TCPSender需要根據收到的包類型進行狀態轉移,并決定發送含有有效數據的報文段還是空 ACK給對方。

為什么即使沒有新的數據要發送也要回復一個空 ACK呢?因為如果不這么做,對方會以為剛剛發的包丟掉了而一直重傳。

void TCPConnection::segment_received(const TCPSegment &seg) {    if (!active())        return;    _last_segment_time = 0;    // 是否需要發送空包回復 ACK,比如沒有數據的時候收到 SYN/ACK 也要回一個 ACK    bool need_empty_ack = seg.length_in_sequence_space();    auto &header = seg.header();    // 處理 RST 標志位    if (header.rst)        return abort();    // 將包交給發送者    if (header.ack) {        need_empty_ack |= !_sender.ack_received(header.ackno, header.win);        // 隊列中已經有數據報文段了就不需要專門的空包回復 ACK        if (!_sender.segments_out().empty())            need_empty_ack = false;    }    // 將包交給接受者    need_empty_ack |= !_receiver.segment_received(seg);    // 被動連接    if (TCPState::state_summary(_receiver) == TCPReceiverStateSummary::SYN_RECV &&        TCPState::state_summary(_sender) == TCPSenderStateSummary::CLOSED)        return connect();    // 被動關閉    if (TCPState::state_summary(_receiver) == TCPReceiverStateSummary::FIN_RECV &&        TCPState::state_summary(_sender) == TCPSenderStateSummary::SYN_ACKED)        _linger_after_streams_finish = false;    // LAST_ACK 狀態轉移到 CLOSED    if (TCPState::state_summary(_receiver) == TCPReceiverStateSummary::FIN_RECV &&        TCPState::state_summary(_sender) == TCPSenderStateSummary::FIN_ACKED && !_linger_after_streams_finish) {        _is_active = false;        return;    }    if (need_empty_ack && TCPState::state_summary(_receiver) != TCPReceiverStateSummary::LISTEN)        _sender.send_empty_segment();    // 發送其余報文段    send_segments();}
測試

在終端中輸入 make check_lab4就能運行所有測試用例,測試結果如下:

發現有幾個 txrx.sh的測試用例失敗了,但是單獨運行這些測試用例卻又可以通過,就很奇怪:

接著測試一下吞吐量(請確保構建類型是 Release 而不是 Debug),感覺還行, 0.71Gbit/s,超過了實驗指導書要求的 0.1Gbit/s。但是實際上還可以優化一下 ByteStream類,將內部數據類型換成 BufferList,這樣在寫入數據的時候就不用一個字符一個字符插入隊列了,可以大大提高效率。

最后將 Lab0 中 webget使用的 TCPSocket換成 CS144TCPSocket,重新編譯并運行 webegt,發現能夠正確得到響應結果,說明我們實現的這個 CS144TCPSocket已經能和別的操作系統實現的 Socket進行交流了:

后記

至此,CS144 的 TCP 實驗部分已全部完成,可以說是比較有挑戰性的一次實驗了,尤其是 Lab4 部分,各種奇奇怪怪的 bug,編碼一晚上,調試時長兩天半(約等于一坤天),調試的時候斷點還總是失效,最后發現是優化搞的鬼,需要將 etc/cflags.cmake第 18 行改為 set (CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -ggdb3 -O0")才行。以上~~

關鍵詞:

免責聲明:本網站所有信息,并不代表本站贊同其觀點和對其真實性負責,投資者據此操作,風險請自擔。

相關閱讀
亚洲精品永久视频_久久精品视频16_亚洲精品永久视频_日韩黄色片在线_五月天综合婷婷_懂色av一区二区三区四区五区_www.这里只有精品_国产成人久久婷婷精品流白浆_久久久九九九热_国产一区亚洲二区三区_日韩中字在线观看_男女猛烈激情xx00免费视频
日韩激情精品| 在线日韩欧美| 国产乱码午夜在线视频| 亚洲在线国产日韩欧美| 国产 日韩 欧美 综合 一区| 欧美国产91| 成人一区而且| 欧美自拍一区| 日韩精品一卡二卡三卡四卡无卡| 福利在线免费视频| 国产精品v亚洲精品v日韩精品| 日韩精品一卡二卡三卡四卡无卡| 欧美天堂视频| 福利一区二区免费视频| 国产亚洲精品美女久久| 欧美资源在线| 日韩一区二区久久| 香蕉精品久久| 国产亚洲一区二区手机在线观看 | 国产精品不卡| 国产精品tv| 日韩精品欧美大片| 一区二区三区午夜视频| 亚洲一区二区三区高清不卡| 秋霞国产精品| 国产网站在线| yellow在线观看网址| 国内一区二区三区| 国模精品一区| 亚洲黄色免费av| 日韩中文首页| 欧美精品黄色| 免费在线观看不卡| 日韩精品乱码av一区二区| 亚洲一区黄色| 日韩精品一区二区三区中文| 日韩av一级片| 欧美三级第一页| 国产亚洲欧美日韩在线观看一区二区 | 精品美女视频 | 日韩综合小视频| 香蕉国产精品| 国产成人久久| 国产v日韩v欧美v| 日韩欧美字幕| 伊人久久婷婷| 亚洲天堂日韩在线| 国产日韩一区二区三区在线播放| 国产精品一区高清| 日韩国产一区二区三区| 欧美日韩高清| 日韩精品视频在线看| 国产精品大片免费观看| 另类专区亚洲| 丝袜美腿亚洲一区二区图片| 国产欧美在线观看免费| 不卡专区在线| 久久精品播放| 五月激激激综合网色播| 久久亚洲道色| 日韩一级欧洲| 精品国产午夜肉伦伦影院 | 国产亚洲久久| 国产亚洲一区二区手机在线观看| 国产美女精品| 久久久久九九精品影院| 久久精品观看| 国产情侣久久| 尤物精品在线| 91嫩草亚洲精品| 视频在线在亚洲| 国产精品成人国产| 免费精品国产| 久久尤物视频| 亚洲字幕久久| 午夜影院一区| 日韩激情中文字幕| 黄色av日韩| 精品99在线| 日本亚州欧洲精品不卡| av一区在线| 麻豆久久久久久久| 另类av一区二区| 久久人人97超碰国产公开结果| 人人爱人人干婷婷丁香亚洲| 99久久精品网| 久久精品国产网站| 日韩精品视频一区二区三区| 九九综合九九| 日韩大片在线播放| 国产精品亚洲片在线播放| 好吊日精品视频| 成人日韩在线观看| 精品一区av| 69堂精品视频在线播放| 9国产精品视频| 91精品国产自产在线观看永久∴| 国产精成人品2018| 亚洲精品护士| 久久亚洲色图| 99国产精品自拍| 久久国产直播| 久久精品av| 99久久婷婷| 啪啪国产精品| 日韩免费一区| 国产美女高潮在线| 你懂的国产精品| 国产精品二区影院| 免费在线播放第一区高清av| 日本aⅴ精品一区二区三区| 亚洲午夜精品久久久久久app| 中文字幕在线官网| 不卡专区在线| 日韩一区二区三区在线免费观看| 久久精品欧洲| 久久精品三级| 中文字幕成在线观看| 91av亚洲| 99热国内精品| 另类av一区二区| 日韩国产在线不卡视频| 久久精品国内一区二区三区水蜜桃| 婷婷综合激情| 国产精品极品在线观看| 国产一区观看| 国产日产一区| 国产精品日韩| 日韩精品91| 日本三级亚洲精品| 日韩亚洲一区在线| 爽好久久久欧美精品| 国产不卡人人| 日韩国产高清在线| 欧美日韩在线二区| 久久精品国产久精国产爱| 免费久久99精品国产自在现线| 欧美国产不卡| 一区二区三区国产在线| 色婷婷精品视频| 国产精品亚洲片在线播放| 婷婷精品进入| 91视频精品| 日韩av中文字幕一区二区三区| 中文字幕系列一区| 国产亚洲一卡2卡3卡4卡新区| 日韩黄色大片| 国产精品sm| 日韩精品一页| 日韩中文字幕一区二区三区| 视频福利一区| 日韩成人精品一区| 欧美日韩中文| 中文无码日韩欧| 午夜精品婷婷| 欧美日韩一区二区综合| 国产a久久精品一区二区三区| 日韩午夜视频在线| 亚洲专区一区| 激情婷婷亚洲| 欧美sss在线视频| 精品国产乱码久久久久久樱花 | 欧美日韩一二三四| 97人人精品| 免费亚洲婷婷| 国产精品久久久一区二区| 亚洲另类黄色| 一区二区三区四区在线观看国产日韩 | 精品欧美日韩精品| 久久国产三级精品| 日韩精品a在线观看91| 亚洲在线久久| 中文字幕日韩高清在线| 好看不卡的中文字幕| 日本欧美不卡| 在线观看精品| 91精品在线观看国产| 久久免费高清| 国精品一区二区| 精品91久久久久| 亚洲专区一区| 日韩精品一页| 国产精品激情电影| 精品视频在线你懂得| 国产 日韩 欧美 综合 一区| 国产精品九九| 97在线精品| 日韩精品影视| 黄色国产精品| 日韩精品免费视频一区二区三区| 青青草国产精品亚洲专区无| 国产日韩1区| 国产精品久久久久久久久久10秀| 91日韩欧美| 狠狠久久婷婷| 亚洲毛片网站| 国产欧美自拍一区| 日韩精品1区| 午夜电影亚洲| 日韩一区二区三区免费视频|