(网络编程笔记):TCP状态转换图、端口复用、半关闭状态、心跳包

目录

TCP状态转换

端口复用

半关闭状态

心跳包

TCP状态转换

  • 了解TCP状态转换图可以帮助开发人员查找问题.
  • 说明: 上图中粗线表示主动方, 虚线表示被动方, 细线部分表示一些特殊情况, 了解即可, 不必深入研究.
  • 对于建立连接的过程客户端属于主动方, 服务端属于被动接受方(图的上半部分)
  • 对于关闭(图的下半部分), 服务端和客户端都可以先进行关闭.
  • 处于ESTABLISHED状态的时候就可以收发数据了, 双方在通信过程当中一直处于ESTABLISHED状态, 数据传输期间没有状态的变化.
  • TIME_WAIT状态一定是出现在主动关闭的一方
  • 主动关闭的Socket端会进入TIME_WAIT状态,并且持续2MSL时间长度,MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。

使用netstat -anp可以查看连接状态

注:数据传输的时候带了一个字节的数据, 所以server发送给client的ACK=x+2

  • 三次握手过程:
    • 客户端: SYN_SENT---connect()   
    • 服务端: LISTEN--listen()   SYN_RCVD
    • 当三次握手完成后, 都处于ESTABLISHED状态 

  • 数据传输过程中:状态不发生变化, 都是ESTABLISHED状态

  • 四次挥手过程:
    • 主动关闭方: FIN_WAIT_T  FIN_WAIT_2 TIME_WAIT
    • 被动关闭方: CLOSE_WAIT  LAST_ACK

  • 注意:
    • SYN_SENT状态出现在哪一方? 客户端
    • SYN_RCVD状态出现在哪一方? 服务端
    • TIME_WAIT状态出现在哪一方?  主动关闭方
    • 在数据传输的时候没有状态变化.
    • TIME_WAIT是如何出现的:
      • 启动服务端, 启动客户端, 连接建好, 而且也可以正常发送数据;
      • 然后先关闭服务端, 服务端就会出现TIME_WAIT状态.

为什么需要2MSL?

  • 原因之一: 让四次挥手的过程更可靠, 确保最后一个发送给对方的ACK到达;
    • 若对方没有收到ACK应答, 对方会再次发送FIN请求关闭, 此时在2MS时间内被动关闭方仍然可以发送ACK给对方.
  • 原因之二: 为了保证在2MS时间内, 不能启动相同的SOCKET-PAIR.
    • TIME_WAIT一定是出现在主动关闭的一方, 也就是说2MS是针对主动关        闭一方来说的;由于TCP有可能存在丢包重传, 丢包重传若发给了已经断        开连接之后相同的socket-pair(该连接是新建的, 与原来的socket-pair完        全相同, 双方使用的是相同的IP和端口), 这样会对之后的连接造成困扰,         严重可能引起程序异常.
  • 如何避免问题2呢??
    • 很多操作系统实现的时候, 只要端口被占用, 服务就不能启动.
  • 测试:
    • 启动服务端和客户端, 然后先关闭服务端, 再次启动服务端, 此时服务端报错: bind error: Address already in use;
    • 若是先关闭的客户端, 再关闭的服务端, 此时启动服务端就不会报这个错误.
  • socket-pair的概念: 客户端与服务端连接其实是一个连接对, 可以通过使用netstat -anp | grep 端口号 进行查看.

端口复用

  • 解决端口复用的问题: bind error: Address already in use, 发生这种情况是在服务端主动关闭连接以后, 接着立刻启动就会报这种错误.

setsockopt函数

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
setsockopt(lfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(int));
  • 函数说明可参看<<UNIX环境高级编程>>
  • 由于错误是bind函数报出来的, 该函数调用要放在bind之前, socket之后

半关闭状态

半关闭的概念:

  • 如果一方close, 另一方没有close, 则认为是半关闭状态, 处于半关闭状态的时候, 可以接收数据, 但是不能发送数据. 相当于把文件描述符的写缓冲区操作关闭了.
  • 注意: 半关闭一定是出现在主动关闭的一方.

shutdown函数

长连接和短连接的概念

  • 长连接: 连接建立好之后,一直保持连接不关闭
  • 短连接: 连接使用完之后就立刻关闭.

shutdown和close的区别:

  • shutdown可以实现半关闭, close不行
  • shutdown关闭的时候, 不考虑文件描述符的引用计数, 是直接彻底关闭
    • close考虑文件描述符的引用计数, 调用一次close只是将引用计数减1, 
    • 只有减小到0的时候才会真正关闭.
    • 如: 调用dup函数或者dup2函数可以复制一个文件描述符, close其中一个并不影响另一个文件描述符, 而shutdown就不同了, 一旦shutdown了其中一 个文件描述符, 对所有的文件描述符都有影响 

心跳包

  • 什么是心跳包?
    • 用于监测长连接是否正常的字符串.
  • 在什么情况下使用心跳包?
    • 主要用于监测长连接是否正常.
  • 如何使用心跳包?
    • 通信双方需要协商规则(协议), 如4个字节长度+数据部分
  • 方法1:
keepAlive = 1;
setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
  • 由于不能实时的检测网络情况, 一般不用这种方法
  • 方法2:
    • 在应用程序中自己定义心跳包, 使用灵活, 能实时把控.

  • 【注】:参考黑马linux C++教程
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值