[置顶] NS2中对TCP数据包和ACK包的TCP Sink类的主要实现代码详尽剖析--吐血放送

时间:2021-06-16 03:06:23

NS2中对TCP数据包和ACK包的TCP Sink类的主要实现代码详尽剖析,限于个人水平,如有错误请留言指出!

TcpSink类的recv()方法:

void TcpSink::recv(Packet* pkt, Handler*)
{
int numToDeliver;
int numBytes = hdr_cmn::access(pkt)->size();//接收到的包的大小
// number of bytes in the packet just received
hdr_tcp *th = hdr_tcp::access(pkt);//定义接收到的包头位指针
/* W.N. Check if packet is from previous incarnation */
if (th->ts() < lastreset_) {//说明该包是无效的包
// Remove packet and do nothing
Packet::free(pkt);//删除该包
return;
}
acker_->update_ts(th->seqno(),th->ts(),ts_echo_rfc1323_);//更新接收端确认器,更新内容:包的序列号、到达时间,相应的时间戳
// update the timestamp to echo numToDeliver = acker_->update(th->seqno(), numBytes);//把更新的序列号和字节数,给变量numToDeliver用于计算recv窗口
// update the recv window; figure out how many in-order-bytes
// (if any) can be removed from the window and handed to the
// application
if (numToDeliver) {//应用程序对变量numToDeliver处理
bytes_ += numToDeliver;
recvBytes(numToDeliver);
}
// send any packets to the application
ack(pkt);//回应该包的ACK
// ACK the packet
Packet::free(pkt);
// remove it from the system
}

TcpSink类的ack()方法:

void TcpSink::ack(Packet* opkt)
{
Packet* npkt = allocpkt();//opkt是指刚接收到的数据包,npkt是即将构建的该数据包的对应ACK包
// opkt is the "old" packet that was received
// npkt is the "new" packet being constructed (for the ACK)
double now = Scheduler::instance().clock();//获取当前时间用于ACK包 hdr_tcp *otcp = hdr_tcp::access(opkt);//接收到的数据包的TCP包头指针
hdr_ip *oiph = hdr_ip::access(opkt);//接收到的数据包的IP包头指针
hdr_tcp *ntcp = hdr_tcp::access(npkt);//将要构建的ACK包的TCP包头指针 if (qs_enabled_) {//如果可以进行快速启动,进行以下相关处理
// QuickStart code from Srikanth Sundarrajan.
hdr_qs *oqsh = hdr_qs::access(opkt);
hdr_qs *nqsh = hdr_qs::access(npkt);
if (otcp->seqno() == 0 && oqsh->flag() == QS_REQUEST) {
nqsh->flag() = QS_RESPONSE;
nqsh->ttl() = (oiph->ttl() - oqsh->ttl()) % 256;
nqsh->rate() = oqsh->rate();
}
else {
nqsh->flag() = QS_DISABLE;
}
} // get the tcp headers
ntcp->seqno() = acker_->Seqno();//序列号填充ACK???
// get the cumulative sequence number to put in the ACK; this is just the left edge of the receive window - 1
ntcp->ts() = now;//将时间填充到ACK的TCP包头
// timestamp the packet if (ts_echo_bugfix_) /* TCP/IP Illustrated, Vol. 2, pg. 870 */ //以下对是否启用时间戳的处理
ntcp->ts_echo() = acker_->ts_to_echo();
else
ntcp->ts_echo() = otcp->ts();
// echo the original's time stamp hdr_ip* oip = hdr_ip::access(opkt);//接收到的数据包的IP包头指针
hdr_ip* nip = hdr_ip::access(npkt);//用于构建的ACK包的IP包头指针
// get the ip headers
nip->flowid() = oip->flowid();//接收到的数据包的IP包的ID赋给构建的ACK包的IP包头
// copy the flow id hdr_flags* of = hdr_flags::access(opkt);//接收到的数据包的包标记指针
hdr_flags* nf = hdr_flags::access(npkt);//构建的ACK包的包标记指针
hdr_flags* sf; //接收端已经存储的包标记指针,主要用于对延迟包的处理,无需详细解释
if (save_ != NULL)
sf = hdr_flags::access(save_);
else
sf = 0;
// Look at delayed packet being acked.
if ( (sf != 0 && sf->cong_action()) || of->cong_action() ) //如果接收端有已经存储的包标记且该标记的拥塞响应位为真或者刚收到的新数据包的拥塞响应位为真,后一种情况是研究重点
// Sender has responsed to congestion.
acker_->update_ecn_unacked(0);//确认器将未确认的拥塞指示置为已经确认(即没有没确认,有点拗口,但就是这样理解)
if ( (sf != 0 && sf->ect() && sf->ce()) || (of->ect() && of->ce()) )//如果接收端有已经存储的包标记且该标记的ECT位和CE位都为真或者刚收到的数据包的标记的ECT位和CE位都为真,也就是说该包到达接收端的过程中经历量拥塞,后一种情况是研究重点
// New report of congestion.
acker_->update_ecn_unacked(1);//确认器将未确认的拥塞指示置为未确认
if ( (sf != 0 && sf->ect()) || of->ect() )//如果接收端有已经存储的包标记且该包标记的ECT位为真或者刚收到的新数据包的标记的ECT位为真,此时并没有考虑CE位的真假,后者为研究重点
// Set EcnEcho bit.
nf->ecnecho() = acker_->ecn_unacked();//将确认器的已经存在的位赋值给即将构建的ACK包的标记位ECN-Echo
if (!of->ect() && of->ecnecho() || (sf != 0 && !sf->ect() && sf->ecnecho()) ) {//如果刚收到的新的数据包的标记的ECT位为假且ECN-Echo位为真或者接收端有已经存储的包标记且该标记的ECT位位假且ECN-Echo位为真,简而言之,该包到达接收端过程中没有经历拥塞,同时对响应的带有ECE位的ACK做出了响应
// This is the negotiation for ECN-capability.
// We are not checking for of->cong_action() also.
// In this respect, this does not conform to the specifications in the internet draft
nf->ecnecho() = 1;//直接将即将构建的ACK包的标记的ECN-Echo位置1
if (ecn_syn_) //如果是TCP连接刚建立时
nf->ect() = 1; //将即将构建的ACK包的标记的ECT位置1,不是研究重点
}
//下面两行是对非对称的TCP连接的特殊处理,无需研究
acker_->append_ack(hdr_cmn::access(npkt),ntcp, otcp->seqno());
add_to_ack(npkt);
// the above function is used in TcpAsymSink // Andrei Gurtov 用于记录序列号
acker_->last_ack_sent_ = ntcp->seqno();
// printf("ACK %d ts %f\n", ntcp->seqno(), ntcp->ts_echo()); send(npkt, 0);//发送该ACK包
// send it
}

[置顶] NS2中对TCP数据包和ACK包的TCP Sink类的主要实现代码详尽剖析--吐血放送的更多相关文章

  1. &lbrack;置顶&rsqb; NS2中TCP拥塞控制仿真过程中盲点解析

    最近利用NS2做TCP拥塞控制协议的仿真,发现很多变量的方法含义都是解释的不清楚,给核心模块修改带来很多麻烦,所以决定用最准确的语言解释成员变量.方法,术语等的含义.限于个人水平,若有错误请留言指正! ...

  2. &lbrack;置顶&rsqb; DataGridView控件---绑定数据方法

             DataGridView控件是在windows应用程中显示数据最好的方式,它只需要几行简短的代码就可以把数据显示给用户,同时又支持增.删.改操作.今天将自己总结的增加数据的方法总结分 ...

  3. &lbrack;置顶&rsqb; JSP中使用taglib出错终极解决办法

    jsp中 <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %> <c ...

  4. java加载外部文件数据到代码中:外部数据文件放到jar包中,调用方法getResourceAsStream

    任务要将数据文件geo.txt加载进行.因为是别人写的总体项目,不能乱动位置.只能将geo.txt打包到jar中某目录.比如,放到.class文件下怎么加载:http://riddickbryant. ...

  5. &lbrack;置顶&rsqb;&NewLine; MVC中使用signalR入门教程

    一.前言:每次写总要说一点最近的感想 进入工作快半年了,昨天是最郁闷的一天,我怀疑我是不是得了"星期一综合征",每个星期一很没有状态.全身都有点酸痛,这个可能一个星期只有周末才打一 ...

  6. &lbrack;置顶&rsqb; linux中fork()函数详解(原创!!实例讲解)

    分类: 计算机系统 linux2010-06-01 23:35 60721人阅读 评论(105) 收藏 举报 linux2010存储  一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源 ...

  7. &lbrack;置顶&rsqb; Jquery中DOM操作(详细)

    Jquery中的DOM操作 为了能全面的讲解DOM操作,首先需要构建一个网页. HTML代码: <%@ page language="java" import="j ...

  8. &lbrack;置顶&rsqb; Flex中Tree组件无刷新删除节点

    在Tree组件中经常要删除某个节点,而删除之后重新刷新加载该Tree组件会影响整个操作效果和效率,因此,无刷新删除就比较好,既删除了节点也没有刷新tree,而使Tree的状态处于删除之前的状态. 无刷 ...

  9. &lbrack;置顶&rsqb; mysql中的set和enum类型的用法和区别

    mysql中的enum和set其实都是string类型的而且只能在指定的集合里取值,  不同的是set可以取多个值,enum只能取一个值.   CREATE TABLE `20121101_t` ( ...

随机推荐

  1. Visual Studio 不生成&period;vshost&period;exe和&period;pdb文件的方法【转】

    Visual Studio 不生成.vshost.exe和.pdb文件的方法[转] 使用Visual Studio编译工程时,默认设置下,即使选择了「Release」时也会生成扩展名为「.vshost ...

  2. Allow windows service to &quot&semi;Interact with desktop&quot&semi;

    Typically, services are designed to run unattended without any UI with any need to interact with des ...

  3. debug 输出 以及宏定义--备

    使用NSLog的一个风险是:它的运行会占用时间和设备资源. 所以在编译版本前一定不要有nslog. 同时当你的工程中有很多log 输出的时候 查找起来很不方便 ,下面介绍一种方法 可以使我们事半功倍. ...

  4. Java版冒泡排序和选择排序

    一.理解说明 1.理解和记忆 冒泡排序:依次定位数组元素,每次只和相邻的且符合条件的元素交换位置. 选择排序:依次在数组的每个位置,通过逐个对比选择出最大或最小的元素. 2.知识点说明 (1)数组是引 ...

  5. SpringMVC原理及非注解配置详解

    1. Spring介绍 Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简单. 这些控制器 ...

  6. 一个Fragment的实例

    @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method s ...

  7. openstack Ocata版本 python

    from keystoneauth1.identity import v3 from keystoneauth1 import session from novaclient import clien ...

  8. oracle 11&period;2&period;0&period;4 rac 打补丁

    本次安装pus环境是11.2.0.4 rac,打的patch为11.2.0.4.180717 (Includes Database PSU),gi补丁和数据库补丁一起打 安装最新opatch版本 un ...

  9. Android 两级菜单栏

    这里来记录下,android 的两级菜单栏,就是顶部切换,和底部的切换.因为在这个上面整了太久的时间,所以特此记录下. 第一种: 先介绍一个网上别人写出来的效果吧,这个当时积分真的很高..CSDN30 ...

  10. flask第二十篇——模板【3】

    请关注公众号:自动化测试实战 现在我们通过查询字符串的方式给render_template传参,我们就要用到flask库的flask.request.args.get()函数先获取参数,在index. ...