• TCP中需要了解的东西


    1.TCP是一个流协议.

    TCP跟UDP不一样的是,TCP发送过去的东西是stream,也就是说第一次发送的跟第二次发送的数据包可能会粘在一起,即所谓的粘包问题
     
    解决粘包问题一般有两个方法
    1.在两次发包的间隔sleep一段时间,很不稳定的方法,因为接收方可能会阻塞,导致两次发送的包还是粘在一起了
     
    2.在每一个包添加包头,现在比较常用的方法,在每个发送的包前面添加包的长度,发送的包类似于下面的结构体:
    struct pack
    {
         size_t len;
         char *data;
    };
     
    然后在接收方处理进行分包
     
    我自己想的一个方法,是为了减少拆包和分包的繁琐的方法,也可以减少需要memcpy的
     
    改成这样的方式:
    发送方首先发送一个包的长度,然后再发送包的数据内容,因为TCP是保证包的顺序到达的,所以接收方首先收到的第一个数据一定是一个下次要接收的包的长度,然后再开始接收包的内容
     
    当然这种方法可以简化拆包和组包的繁琐,但是也会导致多次系统调用
    在发送方,现在我们多了一次write的系统的调用,少了一次memcpy的调用
    在接收方,在比较"坏的情况"下,我们需要两次read才能把数据读出来,为什么说"坏的情况",因为大部分书有说TCP只有在缓冲区满的时候才会发送,虽然我们可以设置强制发送,但是我自己测试了下,这个并不是一定的,可能4个字节TCP也是直接发送出去了,如果接收方立即响应的话,接收方会先read到数据的长度,然后再read到数据
     
    所以这种方法可以减少组包和拆包的繁琐以及memcpy,但因为多次的系统调用,所以不见得是比较好的方法
     
    2.TCP的性能不一定比UDP差
    要了解这个首先要了解三个知识:
    1.MTU,即Maximum Transmission Unit,每次最大传输单元,就是在发送数据的时候,每一次发送给对方的最大数据包大小,如果超过这个大小,数据包会被分割成小的数据包
     
    2.TCP在发送的时候,并不是立即发送,而是会等待一些特定的条件(也可以强制立即发送),比如隔断时间发送,包到一定的大小才会发送,也就说我们在write多个数据包以后,TCP可能会把包组合在一起发送,这个就是会导致粘包的一个原因
     
    3.UDP是立即发送的,不会对包进行额外的处理
     
    这样的话就会有这么一种情况:假如我们的MTU是1500,而我们发送的数据包每次是100 byte,那么UDP分成了15次发送,而TCP可能会让数据的大小到了一个的临界点后才发送,这样就少了很多次的系统的调用,在效率上自然比UDP高
     
    书上是这样说的,但是因为TCP的一些特性,TCP需要双方去维护,在发送包的时候和接收包的时候都需要额外的处理,所以不见得这个理论是正确的,但我觉得这种东西还是要自己去测试才比较好看见区别,我自己测试UDP的性能只比TCP高一点点,并没有什么显著的区别,当然我测试的是单个连接的,有一些情况就比较复杂,比如有2000+条TCP连接,可能操作系统维护起来会比较吃力
     
    3.TCP并非是完全可靠的
    TCP为我们做了很多的工作,让我们保证数据包完整地送到接收方,但是也仅仅是能保证到数据包到达了对方的电脑,但是无法保证数据包到达对方的应用程序并被处理,如果接收方的TCP收到数据包后,发送ACK标志给发送方,发送方会认为接收方已经收到了数据,但是如果此时接收方的OS崩溃或者应用程序崩溃,那么发送方无法知道接收方是否处理了这个数据包
     
     
    4.TCP没有即时通知网络中断的功能
    如果在网络絮乱的情况下,或者网线被人切断的情况下,那么TCP是不会通知应用层的,之所以不提供这样的功能,是因为接收方和发送方的连接线路并不是唯一的,路由器会自动寻找通往另外一方的路径,然后将线路改为另外一条线线路,这样就保证了TCP协议在网络暂时出现问题的情况下依然提供通讯的能力以及自我维护的能力
     
    5.TCP的写操作
    当调用一个write的时候,TCP只是把数据从用户态复制到内核态,然后等待内核去处理,如果在处理的过程中发生错误,比如因为发送失败太多次而丢弃包,用户并无法知道,所以write成功返回仅仅是告诉用户数据成功从用户态复制到 内核态
     
    TCP的实际传输数据取决于缓冲区空间的大小以及网络拥塞以及TCP重传策略等等,但这些东西用户态并无法知道
  • 相关阅读:
    zookeeper基础笔记
    基于spring@aspect注解的aop实现
    Struts2中的开启AsyncContext的方法
    在执行gem install redis时 : ERROR: Error installing redis: redis requires Ruby version >= 2.2.2
    ConcurrentHashMap原理笔记
    Java并发Condition原理分析
    CountDownLatch实现原理
    ThreadPoolExecutor 线程池原理分析
    HashMap原理
    线程池的用法
  • 原文地址:https://www.cnblogs.com/linyilong3/p/3407321.html
Copyright © 2020-2023  润新知