网络基础

    每个TCP套接字在被创建的时候内核都会给该套接字创建一个输入缓冲和一个输出缓存,不同的操作系统输入缓存和输出缓存的大小都是不同的,通过getsockopt函数可以获取输入输出缓存的大小,通过setsockopt函数也可以设置输入输出缓存的大小,但是有最大值和最小值,TCP首部中的窗口字段占16bit,切勿混淆,TCP的发送窗口和接受窗口与发送缓冲与接受缓冲有关系,发送窗口可以说是至于发送缓存中的接受窗口时至于接受缓冲中的,切勿任务发送窗口就是发送缓冲,接受窗口就是接受缓冲,正确的关系是,发送窗口大小小于等于发送缓冲,接受缓冲同理,且发送和接受窗口是不断变化,发送接受缓冲大小是不变(在我们不设置的情况下),窗口机制是为了保证TCP可靠传输的,提高数据通信的效率,且还能流量控制, 窗口应该只是在对应缓存中的一个控制结构,至于通信所需要协商的参数,会在三次握手时协商。![在这里插入图片描述](https://img-blog.csdnimg.cn/20191206141508631.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3Rhb2xhb2Rhd2hv,size_16,color_FFFFFF,t_70)
    TCP套接字也被称为流式套接字,A主机的发送缓存,与B主机的接受换成可以看出一个I/O流,A主机的接受缓存与B主机的发送缓存可以看出一个I/O流,再两台主机建立一条连接后,每台主机就拥独立的输入流和输出流,且TCP套接字是无边界的发送数据时无边界,在刚接触网络编程的时候我们很容易就会认为send函数会直接将数据发送到对方主机,其实不然,在调用send函数时会将应用数据,发送的该套接字的发送缓存中,而不是直接发送到目地主机,也就是说,您使用send函数发送10次数据,目地主机可以一个recv函数就接受,同理,recv函数所作的也只是将(网卡接受数据之后最后会放置输入缓存),recv函数所做的也只不过是从输入缓存中读取数据交给应用层,肯定有人会有疑问了,在send函数将应用数据发送到发送缓存时,发送缓存应该在什么时候把数据发送出去,发送缓存发送数据的时机决定着TCP数据传输的效率,
    机制1.TCP可以选择,维持一个变量,当它等于MSS(最大报文段长的直接发送)。
    机制2.是有发送放的应用进程指明要求发送报文段,即TCP支持的推送操作
    机制3.是一个发送方一个计时器期限到了就把当前已有的缓存数据装入报文段发送,长度不能超过MSS
    明显能感觉到这三种机制都有明显的问题,都有不合理的地方,所以现以未使用,在现实中广泛使用Nagle算法,send函数将应用进程需要发送的输入送入发送缓存,发送方首先将第一个字节数据发送出去,把后面受到的数据先缓存起来,当发送方受到第一个数据字节的确认包受到之后,再把缓存中的数据组装成数据报发送,Nagle算法规定,当到达的数据到达发送窗口一半或已到达报文段最大长度的时,就立即发送一个报文段。	
   
理解了这些TCP套接字的基本知识我们再来看一看输入输出缓存和mbuf之间的关系,为什么会提到mbuf呢,细心的朋友可能注意到上面所讲述的没有提到,应用层数据被分段后,加上运输层首部,传递到网络层,添加网络层首部,等等这些过程是如何进行的,应用层数据必须封装成分组才能在Internet上进行传输。
在谈及mbuf之间我们已经知道数据在网络上传输的单位是帧,而在相邻层之间传输的基本单位是分组,而且在不同的层可能会赋予不同层的首部信息,这就需要一种结构来实现一个mbuf结构来存储数据,在发送数据的时候插口层会将发送缓存中的数据复制到mbuf中,这时候mbuf结构的大小合适就显得尤为重要了,而每个分组数据会存储在一个mbuf链表中,分组的首部会被放置在mbuf链表的头节点中,注意从发送缓存复制到mbuf中的数据只是应用层的数据,没有添加任何首部信息,运输层的输出例程被调用指向mbuf头节点的指针作为参数传递,运输层的输出例程会根据套接字的类型在mbuf头节点的数据部分加上8个字节的UDP首部或是20字节的TCP首部,然后将mbuf传递给IP输出例程,同理IP输出例程会在mbuf头节点添加20个字节的TCP首部,链路层输出例程会添加自己14个字节的以太网首部,高层仅仅添加它们的协议首部并传给下一层,在最底层---设备驱动程序层,mbuf链表中的被放到设备输出队列并重启设备,函数调用相反的顺序返回,而在接受放,网卡每检测到一个数据包到来,会产生一个硬件中断,以太网的设备驱动程序会处理这个中断,接受完成后数据从设备读取中mbuf,调用以太网设备输入例程去除去首部,接着调用IP输出例程去除网络层首部,运输层输入例程去除运输层首部(会根据套接字类型),然后将mbuf中的数据复制到套接字的接受缓存,这个时候我们编写的应用会通过recv从接受缓存中读取指定字节的数据(当我们指定读取字节数大于接受缓存中数据的大小,则读取接受缓存全部数据),我们的应用程序一般只是在应用层,但通过原始套接字可以让我们自己封装IP包,访问底层协议。
 这就是通讯的过程了,肯定的是还有很多的细节没有指出,每一个细节处可能就是一个复杂的算法,如果想要深入的理解协议栈的工作过程,建议去看TCP/IP协议栈的实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值