技巧6:TCP是一种流协议
TCP是一个流协议,跟流水一样,是没有边界的,也就是说如果B端第一次发送100个字节,第二次发送200个字节,当我们读取的时候,是根据缓冲区的大小来看读取结果的,如果我们缓冲区大于300,那么将会把全部读取出来,如果小于300,例如150,则会读取第一个和第二个的50个字节,这样需要我们去处理边界的问题,一般是通过加消息头来确定,而UDP则没有这个问题
技巧9:TCP是个可靠的,但不是完全可靠的
1.假设一个A主机TCP数据包发送给B主机,B主机成功收到,但是还没有复制到应用程序,这个时候B主机已经把ACK已经发给了发送A主机,A主机确认B主机已经接收到数据包,但是B注意在将数据复制到应用程序的时候,崩溃了,应用程序并没有收到数据包。TCP不能保证应用程序B主机收到所有数据,只能保证B主机收到的数据都是无损且按序的(据我所致TCP收到的数据也不能保证无损,因为TCP使用的校验机制不是个很好的算法)
2.网线突然中断,TCP无法检测到,除非中间路由器发送一个ICMP报文,否则无法知道网络是否终端
3.对方突然崩溃,但是自己的应用程序刚好阻塞了,比如A主机和B主机,A主机应用程序突然崩溃了,这个时候A主机发送FIN给B主机,但是B主机在执行fgets函数,被阻塞了,无法处理FIN
技巧10:TCP不是轮询的
TCP无法立即知道连接是否丢失(技巧9说的情况),这样做的原因:
1.是减少网络带宽的耗费
2.灵活,由应用程序来决定是否提供这个功能
3.连接中断可能只是暂时的,比如可能通过查找另外一条路由器路径来修复连接终端的问题
TCP有Keep-live机制,但是对于应用程序来说基本没什么用,主要是通过发送一个包给对方,如果对方收到会发送一个ack给本机,如果超过一定时间没回应则被认为网络中断(也可能要超过一定的次数没回应,BSD是9次没回应则是认为连接终端,两次发送间隔75秒)
一般都是利用心跳来解决应用程序是否中断的问题,有时候会独立一个端口来使用心跳,这样做的好处是可以防止心跳消息与其他消息混杂一起,并且可以防止丢失(技巧6),<<UNIX网络编程>>21.5也有提供TCP紧急心跳的方法
技巧16:
shutdown(int fd,int how)
how = 0:
关闭连接的接收方,即不再接收数据,如果之后有接收数据的操作,则返回EOF
how = 1:
关闭发送方的连接,在将缓冲区的数据发送完以后,才会发送FIN给对方,在缓冲区发送完之前,写操作将错误,这个就是所谓的half close
how = 2:
关闭双方的连接,即shutdown(fd,1)和shutdown(fd,2),但和close不同,shutdown并没有关闭套接字,也没有释放资源,close会减少sockfd的引用技术,只有当引用技术为0的时候对方才会收到FIN,而shutdown则能保证发送fin给对方