Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1390666
  • 博文数量: 1334
  • 博客积分: 645
  • 博客等级: 上士
  • 技术积分: 5762
  • 用 户 组: 普通用户
  • 注册时间: 2012-07-25 16:56
文章分类

全部博文(1334)

文章存档

2014年(108)

2013年(1059)

2012年(169)

分类: LINUX

2013-01-18 19:29:48

原文地址:发送第一个TCP数据报 作者:futter521

  TCP协议发送和接收数据报的过程还是相当的复杂的,这里,我们在完成TCP三次握手协议后,试图避开各种复杂的因素,介绍一个最为简单的TCP数据报发送流程。
    跟UDP,RAW类似,函数mytcp_sendmsg负责发送TCP数据报。首先,要确定最大报文段(MSS)的长度,因为TCP需要把应用数据分割成它认为最为合适的数据块大小,然后传给IP,而不需要IP层再去进行数据报分割,我们得到的MSS是1448。
    接下来我们要进行应用数据的分割,关于应用数据的结构体struct msghdr *msg的介绍,请查阅前面的文章,这里不再重复。
    结构体struct sock有两个成员,sk_write_queue是一个发送队列,有一个或多个待发送的socket缓冲区struct sk_buff排队。sk_send_head指向发送队列中当前需要发送的第一个strcut sk_buff。如果sk_send_head为NULL,则表示当前队列为空,我们需要构建一个新的struct sk_buff来发送我们的应用数据,或者,如果sk_write_queue中最后一个struct sk_buff的长度已经达到MSS的值,则我们也需要构建一个新的struct sk_buff,否则我们可以把新的应用数据添加到sk_write_queue队列中最后一个struct sk_buff中。
    如果要构建新的strcut sk_buff以发送数据,我们首先检查发送缓存是否还有足够的空间,struct sock的成员sk_wmem_queued记录了当前在发送缓存队列sk_write_queue中总的字节数,而成员sk_sndbuf是缓存队列大 小的上限值,如果当前缓存数据已经达上限,则不能再开僻新的套接字缓冲区,必须等待。新创建成功的struct sk_buff加入到sk_write_queue的队列尾,然后把应用数据部分或全部拷到该strcut sk_buff中。
    如果这是本次send系统调用创建的第一个strcut sk_buff,则需要置标志位PSH,表示接收方应该尽快将这个报文段交给应用层。接下来还要更新一些参数,struct tcp_sock的成员write_seq记录的是发送缓冲队列中的最后一个序号,需要加上本次发送的长度,
    完成了一个strcut sk_buff的创建后(或者是在队列中的最后一个sk_buff上添加数据),如果发现,当前队列中最后一个strcut sk_buff的长度还没有达到MSS,则我们继续处理应用数据。如果当前缓冲队列中的最新序号跟发送序号(已经真正发送出去的最后一个序号,由 struct tcp_sock的成员pushed_seq记录)之间的差值大于半个最大滑动窗口的大小,即发送缓冲队列中的的数据已经达到或超过半个滑动窗口了,则必 须先发送一次,再继续处理应用数据。因为滑动窗口是对端通告的本次能一次接收的最大数据量,如果缓冲队列中缓存的数据量太大,超过滑动窗口的大小了,则一 次发送出去,会造成对端的接收有问题。
    发送数据前,先更新struct tcp_sock的成员puashed_seq为write_seq,因为发送时,肯定是要把缓冲队列中的数据全部发送完的,同时,置本次发送的最后一个 数据报的PSH标志。另外,对于一些小数据量,即本次应用数据处理完后,缓存队列中只有一个strcut sk_buff,则也立即发送出去。
    实际的发送处理还会遇到如阻塞算法等复杂问题,暂时不作介绍。
阅读(167) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~