Android高级进阶(腾讯,绿网天下,哔哩哔哩,虎扑工程师联合出品)Android技术知识Android开发经验谈

网络编程(1)-TCP问题分析

2017-12-26  本文已影响97人  ZJ_Rocky

主目录见:Android高级进阶知识(这是总目录索引)
[written by 无心追求]

TCP问题分析

网络的五层协议

TCP协议

TCP三次握手

[图片上传中...(tcp3.jpg-a081f-1513993970933-0)]

[图片上传中...(tcp4.jpg-9173c2-1513993970933-1)]

这边有几个比较重要的点,主机A发起SYN,假设序号Seq为a,发送成功后A进入了SYN_SENT状态,主机B收到A发的SYN后给一个SYN+ACK,发送成功后B进入SYN_RCVD状态,假设序号Seq为b,那么确认号Ack必须为a+1,以此来标记确实收到了A发过来的SYN,同时也说明下一次A要是再发消息过来,那么序号Seq必须是a+1,主机A收到B发过来的SYN+ACK后,进入ESTABLISHED状态,表示A的TCP已经可用,然后再回复一个ACK给B,序号Seq为a+1,确认号Ack为b+1,B收到后状态也变为ESTABLISHED状态,这时候TCP的三次握手就完成了

TCP四次挥手

tcp7.jpg tcp6.jpg

和三次握手比较类似,主机A主动发送FIN,Seq为a,ack为x,然后A进入FIN_WAIT1状态,B进入CLOSE_WAIT状态,主机B收到A发过来的FIN之后,先回复一个FIN+ACK,Seq为b,ack为a+1,然后B进入LAST_ACK状态,主机A收到B发的FIN+ACK后,回复一个ACK,Seq为a+1,Ack为b+1,A进入TIME_WAIT状态,B收到A的ACK后,进入CLOSED,然后A会再等一小段时间(2MSL超时)后进入CLOSED状态,TCP4次挥手完成,其实从抓包来看,并没有发生四次交互,因为B的ACK和FIN合并在一起发出去了,这个也是TCP传输的一种策略,减少一次交互,增加了网络的效率,4次挥手我认为是逻辑上的4个步骤

以下内容都特么是从书里抄的

TCP选项

拥塞控制

Nagle算法
/**
     * Enable/disable TCP_NODELAY (disable/enable Nagle's algorithm).
     *
     * @param on <code>true</code> to enable TCP_NODELAY,
     * <code>false</code> to disable.
     *
     * @exception SocketException if there is an error
     * in the underlying protocol, such as a TCP error.
     *
     * @since   JDK1.1
     *
     * @see #getTcpNoDelay()
     */
    public void setTcpNoDelay(boolean on) throws SocketException {
        if (isClosed())
            throw new SocketException("Socket is closed");
        getImpl().setOption(SocketOptions.TCP_NODELAY, Boolean.valueOf(on));
    }

以上是应用层提供的是否开启Nagle算法的接口,默认为false,即开启Nagle算法


tcp9.jpg tcp10.jpg

这个是未用Nagle算法的抓包信息

滑动窗口
tcp11.jpg

对于发送方来说:

  1. Sent and Acknowledged:这些数据表示已经发送成功并已经被确认的数据,这些数据其实的位置是在窗口之外了,因为窗口内顺序最低的被确认之后,要移除窗口,实际上是窗口进行合拢,同时打开接收新的带发送的数据
  2. Send But Not Yet Acknowledged:这部分数据称为发送但没有被确认,数据被发送出去,没有收到接收端的ACK,认为并没有完成发送,这个属于窗口内的数据
  3. Not Sent,Recipient Ready to Receive:这部分是尽快发送的数据,这部分数据已经被加载到缓存中,也就是窗口中了,等待发送,其实这个窗口是完全有接收方告知的,接收方告知还是能够接受这些包,所以发送方需要尽快的发送这些包
  4. Not Sent,Recipient Not Ready to Receive: 这些数据属于未发送,同时接收端也不允许发送的,因为这些数据已经超出了发送端所接收的范围

对于接收方来说:

  1. Received and ACK Not Send to Process:这部分数据属于接收了数据但是还没有被上层的应用程序接收,也是被缓存在窗口内
  2. Received Not ACK: 已经接收,但是还没有回复ACK,这些包可能输属于Delay ACK的范畴了
  3. Not Received:有空位,还没有被接收的数据

窗口的动态调整:

  1. 客户端给服务器发送了50个字节,然后服务器回了Ack,并且告知Win=0,客户端收到服务器的Ack之后发现服务器这时候已经不能够接收数据了,客户端就会把数据先缓存起来,并不在发送数据,等收到服务器的窗口更新后Win=20,发现服务器重新能够接收20个字节了,这时候客户端才继续发送数据,这里其实也就是流量控制,同时避免过多的数据写入到网络链路中,加入链路的带宽很小,过多的数据写入会造成拥塞
慢启动
拥塞避免
快速重传

超时重传

TCP抓包分析

adb push tcpdump /sdcard/ 
adb Shell 
su 
cat /sdcard/tcpdump > /system/bin/tcpdump

上一条命令如果提示没有权限,接着执行如下命令尝试给 /system 目录增加写权限:

su
mount

在mount结果中找到包含/system的一行,类似如下:

/dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,seclabel,relatime,data=ordered 0 0  

去处/system前半行,即/dev/block/platform/msm_sdcc.1/by-name/system,执行如下命令:

mount -o remount /dev/block/platform/msm_sdcc.1/by-name/system /system

这个时候/system就拥有写权限了,继续执行:

cat /sdcard/tcpdump > /system/bin/tcpdump 
chmod 777 /system/bin/tcpdump  

到此为止,tcpdump就成功安装到了/system/bin/目录下,接着用如下命令还是抓包

Java中的Socket异常分析

connection reset
SocketException: Software caused connection abort
socket closed
SocketTimeoutException:connect timeout/ConnectException: Connection timed out
UnknowHostException
InetSocketAddress inetSocketAddress = new InetSocketAddress(hostInfo.getHostname(), hostInfo.getPort());

这个代码会卡40秒,具体抓包信息如下:


tcp13.jpg
ConnectException:network is unreachable
NoRouteToHostException: No route to host
  1. 自动分配方式(Automatic Allocation),DHCP服务器为主机指定一个永久性的IP地址,一旦DHCP客户端第一次成功从DHCP服务器端租用到IP地址后,就可以永久性的使用该地址
  2. 动态分配方式(Dynamic Allocation),DHCP服务器给主机指定一个具有时间限制的IP地址,时间到期或主机明确表示放弃该地址时,该地址可以被其他主机使用
  3. 手工分配方式(Manual Allocation),客户端的IP地址是由网络管理员指定的,DHCP服务器只是将指定的IP地址告诉客户端主机
    三种地址分配方式中,只有动态分配可以重复使用客户端不再需要的地址,也就是说动态分配的IP地址是可能被回收的,如果一台设备分配的IP被回收了,那这台设备的网络就不可用,这时候如果往再和外网去建立socket连接,就会报NoRouteToHostException: No route to host异常,那么为了给IP续约,Android设备中会去实现DHCP协议,定期30分钟去发起一个DHCP请求来更新IP信息,保持设备网络可用,但是当这个DHCP请求失败的时候,此时IP要是过了有效时段,那么这段时间内的设备网络是无法访问外网的,直到DHCP请求重试成功为止
Connection Refused
TCP端口重用
socket read返回-1

tcpdump抓包分析

tcp dup ack
tcp out of order
tcp retransmission
12-17 10:03:40.994  2725  2960 I SYNC-PUSH: {ConnectionService$7.onWrite--1} write [107] bytes.

12-17 10:04:02.234  2725  3052 I SYNC-PUSH: {ConnectionService$7.onWrite--1} write [7] bytes.
tcp14.jpg

应用层将107字节发写入之后,发生了重传,这时候在10:04:02秒又写入7个字节,我们在抓包的时候发现重传并没有把这7个字节一起发送出去,说明这个7个字节被暂时缓存起来了,此时有可能是网络拥塞了,所以就不再向链路中发送数据避免加重网络拥塞,如果此时并不是网络拥塞,那么有可能这7个字节就在重传过程中被一起发送出去

tcp fast retransmission
tcp previous segment not captured

上图,发生tcp previous segment not captured的消息包Sequence number: 1242674817,重传的消息包Sequence number: 1242674796,但是1242674817先到了,而1242674796后到,所以在收到1242674817的时候会提示有漏掉一个segment数据,1242674817会缓存起来并不会马上通知给应用层,直到1242674796到了之后一起通知给应用层

seq,ack,tsval,tsecr
上一篇下一篇

猜你喜欢

热点阅读