99久久精品日本一区二区免费,五级黄高潮片90分钟视频,娇妻销魂的交换经历,欧美大屁股xxxxhd黑色

您的位置:首頁>熱點(diǎn) >
  • CS144 計(jì)算機(jī)網(wǎng)絡(luò) Lab4:TCP Connection

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

經(jīng)過前面幾個實(shí)驗(yàn)的鋪墊,終于到了將他們組合起來的時候了。Lab4 將實(shí)現(xiàn) TCP Connection 功能,內(nèi)部含有 TCPReceiverTCPSender,可以與 TCP 連接的另一個端點(diǎn)進(jìn)行數(shù)據(jù)交換。


(資料圖)

實(shí)驗(yàn)要求

簡單來說,這次實(shí)驗(yàn)就是要在 TCPConnection類中實(shí)現(xiàn)下圖所示的有限狀態(tài)機(jī):

這些狀態(tài)對應(yīng) TCPState的內(nèi)部枚舉類 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};

除了三次握手和四次揮手外,我們還得處理報(bào)文段首部 RST標(biāo)志被置位的情況,這時候應(yīng)該將斷開連接,并將內(nèi)部的輸入流和輸入流標(biāo)記為 error,此時的 TCPState應(yīng)該是 RESET。

代碼實(shí)現(xiàn)

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

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 發(fā)送報(bào)文段     * @param fill_window 是否填滿發(fā)送窗口    */    void send_segments(bool fill_window = false);    // 發(fā)送 RST 報(bào)文段    void send_rst_segment();    // 中止連接    void abort();  public:    // 省略其余成員}

接著實(shí)現(xiàn)幾個最簡單的成員函數(shù):

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; }
主動連接

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

void TCPConnection::connect() {    // 發(fā)送 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();        // 設(shè)置 ACK、確認(rèn)應(yīng)答號和接收窗口大小        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();    }}
主動關(guān)閉

當(dāng)上層程序沒有更多數(shù)據(jù)需要發(fā)送時,將會調(diào)用 TCPConnection::end_input_stream()結(jié)束輸入,這時候需要發(fā)送 FIN報(bào)文段給服務(wù)端,告訴他自己沒有更多數(shù)據(jù)要發(fā)送了,但是可以繼續(xù)接收服務(wù)端發(fā)來的數(shù)據(jù)??蛻舳说臓顟B(tài)由 ESTABLISHED轉(zhuǎn)移到 FIN_WAIT_1,服務(wù)端收到 FIN之后變成 CLOSE_WAIT狀態(tài),并回復(fù) ACK給客戶端,客戶端收到之后接著轉(zhuǎn)移到 FIN_WAIT_2狀態(tài)。

如果服務(wù)端數(shù)據(jù)傳輸完成了,會發(fā)送 FIN報(bào)文段給客戶端,轉(zhuǎn)移到 LAST_ACK狀態(tài),此時客戶端會回復(fù)最后一個 ACK給服務(wù)端并進(jìn)入 TIME_WAIT超時等待狀態(tài),如果這個等待時間內(nèi)沒有收到服務(wù)端重傳的 FIN,就說明 ACK順利到達(dá)了服務(wù)端且服務(wù)端已經(jīng)變成 CLOSED狀態(tài)了,此時客戶端也能斷開連接變成 CLOSED了。

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

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

主動重置連接

有兩種情況會導(dǎo)致發(fā)送 RST報(bào)文段來主動重置連接:

當(dāng) TCPSender超時重傳的次數(shù)過多時,表明通信鏈路存在故障;TCPConnect對象被釋放但是 TCP 仍然處于連接狀態(tài)的時候;

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

//! \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);    // 重傳次數(shù)太多時需要斷開連接    if (_sender.consecutive_retransmissions() > _cfg.MAX_RETX_ATTEMPTS) {        return send_rst_segment();    }    // 重傳數(shù)據(jù)包    send_segments();    _last_segment_time += ms_since_last_tick;    //  TIME_WAIT 超時等待狀態(tài)轉(zhuǎn)移到 CLOSED 狀態(tài)    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();}
接收報(bào)文段

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

為什么即使沒有新的數(shù)據(jù)要發(fā)送也要回復(fù)一個空 ACK呢?因?yàn)槿绻贿@么做,對方會以為剛剛發(fā)的包丟掉了而一直重傳。

void TCPConnection::segment_received(const TCPSegment &seg) {    if (!active())        return;    _last_segment_time = 0;    // 是否需要發(fā)送空包回復(fù) ACK,比如沒有數(shù)據(jù)的時候收到 SYN/ACK 也要回一個 ACK    bool need_empty_ack = seg.length_in_sequence_space();    auto &header = seg.header();    // 處理 RST 標(biāo)志位    if (header.rst)        return abort();    // 將包交給發(fā)送者    if (header.ack) {        need_empty_ack |= !_sender.ack_received(header.ackno, header.win);        // 隊(duì)列中已經(jīng)有數(shù)據(jù)報(bào)文段了就不需要專門的空包回復(fù) 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();    // 被動關(guān)閉    if (TCPState::state_summary(_receiver) == TCPReceiverStateSummary::FIN_RECV &&        TCPState::state_summary(_sender) == TCPSenderStateSummary::SYN_ACKED)        _linger_after_streams_finish = false;    // LAST_ACK 狀態(tài)轉(zhuǎn)移到 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();    // 發(fā)送其余報(bào)文段    send_segments();}
測試

在終端中輸入 make check_lab4就能運(yùn)行所有測試用例,測試結(jié)果如下:

發(fā)現(xiàn)有幾個 txrx.sh的測試用例失敗了,但是單獨(dú)運(yùn)行這些測試用例卻又可以通過,就很奇怪:

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

最后將 Lab0 中 webget使用的 TCPSocket換成 CS144TCPSocket,重新編譯并運(yùn)行 webegt,發(fā)現(xiàn)能夠正確得到響應(yīng)結(jié)果,說明我們實(shí)現(xiàn)的這個 CS144TCPSocket已經(jīng)能和別的操作系統(tǒng)實(shí)現(xiàn)的 Socket進(jìn)行交流了:

后記

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

關(guān)鍵詞:

免責(zé)聲明:本網(wǎng)站所有信息,并不代表本站贊同其觀點(diǎn)和對其真實(shí)性負(fù)責(zé),投資者據(jù)此操作,風(fēng)險(xiǎn)請自擔(dān)。

相關(guān)閱讀
丰满少妇人妻无码| 久久久久久国产精品免费免费| 中文字幕丰满乱子伦无码专区| 国产毛a片啊久久久久久保和丸| 一本大道熟女人妻中文字幕在线| 亚洲国产精品久久久久秋霞影院| 亚洲午夜av久久久精品影院| 啦啦啦www播放日本观看| 国产av无码专区亚洲av桃花庵| 色综合色狠狠天天综合网| 麻豆国产精品色欲av亚洲三区| 沉沦肉欲的娇妻第十一章| 色综合久久中文综合网| 免费a级毛片无码免费视频| 国产成人无码久久久精品一| 99久久伊人精品综合观看| 亚洲欧洲日产国码无码久久99| 日本免费一区二区三区高清视频| 中文字幕亚洲乱码熟女在线萌芽| 在线永久免费观看黄网站| 又大又粗欧美黑人aaaaa片| 亚洲综合精品香蕉久久网| 啊灬用力灬啊灬啊灬啊灬| 成品网站w灬源码1688小说| 国产综合久久久久| 欧美做爰又粗又大免费看| 帅气体育生gary网站mv软件| 国产AV国产AV在在免费线| 东北女人毛多又黑a片| 男女真人抽搐一进一出免费视频| 随时随地都能干的学校教师| 波多野结衣绝顶大高潮| 差差漫画在线观看登录页面弹窗 | 坐公交忘穿内裤被挺进老外| 宝贝∽好硬∽好爽一再来| 综合网日日天干夜夜久久| 少妇中文字幕乱码亚洲影视| 久久亚洲国产成人精品无码区| 黑人猛挺进小莹的体内视频| 麻豆视传媒官网免费观看| 制服 小说 亚洲 欧美 校园|