51学通信技术论坛

 找回密码
 立即注册
搜索
查看: 4941|回复: 8
打印 上一主题 下一主题

GB口信令分析-重复GET请求疑问 [复制链接]

Rank: 2Rank: 2

跳转到指定楼层
楼主
发表于 2013-9-25 21:21:41 |只看该作者 |倒序浏览
一键分享 一键分享
本帖最后由 78174657 于 2013-9-27 16:41 编辑


这个问题已经困扰我好久了一直解决找不出原因,这是一张采集与GB接口信令的截图,手机发起GET请求后网络回应HTTP响应200OK,之前的流程一直都正常,问题就出在后面,网络发起了FIN ACK请求要求拆除TCP链接,手机也收到了消息并回复了ACK消息,但后续手机又发送了一个包上来,这个包包含了一个GET请求和手机短的FIN ACK消息,这导致第二个GET后续没有任何的接续系统上显示了失败。什么情况导致了手机又一次发起了GET请求,而且是在链路的半闭合状态。访问这个网址的手机都存在这种问题,且其他有些网址也有类似的问题,其中一个有问题的网址我用我自己电脑登入了下并用Wireshark抓了数据包却没有发现这个问题,所以我很困惑...我的思路希望不会打扰到你们的想法,有什么可能性或方法希望大家能帮忙建议一下~~~~拜托了~~
附件: 你需要登录才可以下载或查看附件。没有帐号?立即注册

Rank: 2Rank: 2

沙发
发表于 2013-9-26 09:05:35 |只看该作者
怎么光看没人回答呃

点评

爱卫生  涉及TCP的故障一般都比较麻烦。因为TCP的状态迁移机制本身比较复杂。光凭截图不能完全判断,因此不能随便说两句忽悠你,抱歉。只好找些资料供参考。  发表于 2013-9-26 22:59:54

使用道具 举报

Rank: 9Rank: 9

懒

板凳
发表于 2013-9-26 23:10:47 |只看该作者
78174657 发表于 2013-9-26 09:05
怎么光看没人回答呃

我对TCP理解不是很深,光从截图来看,个人认为,并不能认为是手机行为违规。理由如下:

TCP的连接关闭是四次握手,截图中只显示了是服务器端关闭了连接,代表不会再发送下行数据。而手机在get报文之前并没有主动发FIN报文,因此应该仍是可以继续发上行数据的。所以发了get消息,只不过肯定是没有响应的,因为服务器端已经把下行数据通道关闭了。然后接下来手机发起来了FIN,世界又平静了。

以下是找到的一些资料,供参考,来自于该链接:http://blog.csdn.net/631799/article/details/6995241(这家伙应该是个程序员)

客户端TCP状态迁移:

CLOSED->SYN_SENT->ESTABLISHED->FIN_WAIT_1->FIN_WAIT_2->TIME_WAIT->CLOSED

服务器TCP状态迁移:

CLOSED->LISTEN->SYN收到->ESTABLISHED->CLOSE_WAIT->LAST_ACK->CLOSED

CLOSE_WAIT,TCP的癌症,TCP的朋友。

CLOSE_WAIT状态的生成原因
首先我们知道,如果我们的服务器程序APACHE处于CLOSE_WAIT状态的话,说明套接字是被动关闭的!

因为如果是CLIENT端主动断掉当前连接的话,那么双方关闭这个TCP连接共需要四个packet:

Client ---> FIN ---> Server

Client <--- ACK <--- Server

这时候Client端处于FIN_WAIT_2状态;而Server 程序处于CLOSE_WAIT状态。

Client <--- FIN <--- Server

这时Server 发送FIN给Client,Server 就置为LAST_ACK状态。

Client ---> ACK ---> Server

Client回应了ACK,那么Server 的套接字才会真正置为CLOSED状态。

Server 程序处于CLOSE_WAIT状态,而不是LAST_ACK状态,说明还没有发FIN给Client,那么可能是在关闭连接之前还有许多数据要发送或者其他事要做,导致没有发这个FIN packet。

通常来说,一个CLOSE_WAIT会维持至少2个小时的时间。如果有个流氓特地写了个程序,给你造成一堆的CLOSE_WAIT,消耗

你的资源,那么通常是等不到释放那一刻,系统就已经解决崩溃了。

只能通过修改一下TCP/IP的参数,来缩短这个时间:修改tcp_keepalive_*系列参数有助于解决这个问题。

连接进程是通过一系列状态表示的,这些状态有:LISTEN,SYN-SENT,SYN-RECEIVED,ESTABLISHED,FIN-WAIT-
1,FIN-WAIT-2,CLOSE-WAIT,CLOSING,LAST-ACK,TIME-WAIT和
CLOSED。CLOSED表示没有连接,各个状态的意义如下: LISTEN - 侦听来自远方TCP端口的连接请求; SYN-SENT -
在发送连接请求后等待匹配的连接请求; SYN-RECEIVED - 在收到和发送一个连接请求后等待对连接请求的确认; ESTABLISHED
- 代表一个打开的连接,数据可以传送给用户; FIN-WAIT-1 - 等待远程TCP的连接中断请求,或先前的连接中断请求的确认;
FIN-WAIT-2 - 从远程TCP等待连接中断请求; CLOSE-WAIT - 等待从本地用户发来的连接中断请求; CLOSING -
等待远程TCP对连接中断的确认; LAST-ACK - 等待原来发向远程TCP的连接中断请求的确认; TIME-WAIT -
等待足够的时间以确保远程TCP接收到连接中断请求的确认; CLOSED - 没有任何连接状态;
TCP连接过程是状态的转换,促使发生状态转换的是用户调用:OPEN,SEND,RECEIVE,CLOSE,ABORT和STATUS;传送过来的数
据段,特别那些包括以下标记的数据段SYN,ACK,RST和FIN;还有超时,上面所说的都会时TCP状态发生变化。


2 、连接终止协议(四次握手)
   由于 TCP 连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个 FIN 来终止这个方向的连接。收到一个 FIN 只意味着这一方向上没有数据流动,一个 TCP 连接在收到一个 FIN 后仍能发送数据。首先进行关闭的一方将执行主动关闭,而另一方执行被动关闭。

 ( 1 ) TCP 客户端发送一个 FIN ,用来关闭客户到服务器的数据传送(报文段 4 )。
 ( 2 ) 服务器收到这个 FIN ,它发回一个 ACK ,确认序号为收到的序号加 1 (报文段 5 )。和 SYN 一样,一个 FIN将占用一个序号。
 ( 3 ) 服务器关闭客户端的连接,发送一个 FIN 给客户端(报文段 6 )。
 ( 4 ) 客户段发回 ACK 报文确认,并将确认序号设置为收到序号加 1 (报文段 7 )。

CLOSED: 这个没什么好说的了,表示初始状态。

LISTEN: 这个也是非常容易理解的一个状态,表示服务器端的某个 SOCKET 处于监听状态,可以接受连接了。

SYN_RCVD: 这个状态表示接受到了 SYN 报文,在正常情况下,这个状态是服务器端的 SOCKET 在建立 TCP 连接时的三次握手会话过程中的一个中间状态,很短暂,基本上用 netstat 你是很难看到这种状态的,除非你特意写了一个客户端测试程序,故意将三次 TCP 握手过程中最后一个 ACK 报文不予发送。因此这种状态时,当收到客户端的 ACK 报文后,它会进入到 ESTABLISHED 状态。

SYN_SENT: 这个状态与 SYN_RCVD 遥想呼应,当客户端 SOCKET 执行 CONNECT 连接时,它首先发送 SYN 报文,因此也随即它会进入到了 SYN_SENT 状态,并等待服务端的发送三次握手中的第 2 个报文。 SYN_SENT 状态表示客户端已发送 SYN 报文。

ESTABLISHED :这个容易理解了,表示连接已经建立了。

FIN_WAIT_1: 这个状态要好好解释一下,其实 FIN_WAIT_1 和 FIN_WAIT_2 状态的真正含义都是表示等待对方的 FIN 报文。而这两种状态的区别是: FIN_WAIT_1 状态实际上是当 SOCKET 在 ESTABLISHED 状态时,它想主动关闭连接,向对方发送了 FIN 报文,此时该 SOCKET 即进入到 FIN_WAIT_1 状态。而当对方回应 ACK 报文后,则进入到FIN_WAIT_2 状态,当然在实际的正常情况下,无论对方何种情况下,都应该马上回应 ACK 报文,所以 FIN_WAIT_1 状态一般是比较难见到的,而 FIN_WAIT_2 状态还有时常常可以用 netstat 看到。

FIN_WAIT_2 :上面已经详细解释了这种状态,实际上 FIN_WAIT_2 状态下的 SOCKET ,表示半连接,也即有一方要求close 连接,但另外还告诉对方,我暂时还有点数据需要传送给你,稍后再关闭连接。

TIME_WAIT: 表示收到了对方的 FIN 报文,并发送出了 ACK 报文,就等 2MSL 后即可回到 CLOSED 可用状态了。如果FIN_WAIT_1 状态下,收到了对方同时带 FIN 标志和 ACK 标志的报文时,可以直接进入到 TIME_WAIT 状态,而无须经过 FIN_WAIT_2 状态。

CLOSING: 这种状态比较特殊,实际情况中应该是很少见,属于一种比较罕见的例外状态。正常情况下,当你发送 FIN 报文后,按理来说是应该先收到(或同时收到)对方的 ACK 报文,再收到对方的 FIN 报文。但是 CLOSING 状态表示你发送 FIN 报文后,并没有收到对方的 ACK 报文,反而却也收到了对方的 FIN 报文。什么情况下会出现此种情况呢?其实细想一下,也不难得出结论:那就是如果双方几乎在同时 close 一个 SOCKET 的话,那么就出现了双方同时发送 FIN 报文的情况,也即会出现 CLOSING 状态,表示双方都正在关闭 SOCKET 连接。

CLOSE_WAIT: 这种状态的含义其实是表示在等待关闭。怎么理解呢?当对方 close 一个 SOCKET 后发送 FIN 报文给自己,你系统毫无疑问地会回应一个 ACK 报文给对方,此时则进入到 CLOSE_WAIT 状态。接下来呢,实际上你真正需要考虑的事情是察看你是否还有数据发送给对方,如果没有的话,那么你也就可以 close 这个 SOCKET ,发送 FIN 报文给对方,也即关闭连接。所以你在 CLOSE_WAIT 状态下,需要完成的事情是等待你去关闭连接。

LAST_ACK: 这个状态还是比较容易好理解的,它是被动关闭一方在发送 FIN 报文后,最后等待对方的 ACK 报文。当收到 ACK 报文后,也即可以进入到 CLOSED 可用状态了。

最后有 2 个问题的回答,我自己分析后的结论(不一定保证 100% 正确)

1、 为什么建立连接协议是三次握手,而关闭连接却是四次握手呢?

这是因为服务端的 LISTEN 状态下的 SOCKET 当收到 SYN 报文的建连请求后,它可以把 ACK 和 SYN ( ACK 起应答作用,而 SYN 起同步作用)放在一个报文里来发送。但关闭连接时,当收到对方的 FIN 报文通知时,它仅仅表示对方没有数据发送给你了;但未必你所有的数据都全部发送给对方了,所以你可以未必会马上会关闭 SOCKET, 也即你可能还需要发送一些数据给对方之后,再发送 FIN 报文给对方来表示你同意现在可以关闭连接了,所以它这里的 ACK 报文和 FIN 报文多数情况下都是分开发送的。

2、 为什么 TIME_WAIT 状态还需要等 2MSL 后才能返回到 CLOSED 状态?

这是因为:虽然双方都同意关闭连接了,而且握手的 4 个报文也都协调和发送完毕,按理可以直接回到 CLOSED 状态(就好比从 SYN_SEND 状态到 ESTABLISH 状态那样);但是因为我们必须要假想网络是不可靠的,你无法保证你最后发送的 ACK 报文会一定被对方收到,因此对方处于 LAST_ACK 状态下的 SOCKET 可能会因为超时未收到 ACK 报文,而重发 FIN 报文,所以这个 TIME_WAIT 状态的作用就是用来重发可能丢失的 ACK 报文,并保证于此。

www.gprshome.com: GPRS及移动通信技术学习交流分享平台。

使用道具 举报

Rank: 3Rank: 3Rank: 3

乐于助人

地板
发表于 2013-9-27 15:38:49 |只看该作者
楼主能否把抓包发一下大家分析。

我认为发生这种情况完全是手机应用程序的问题,与Gb无关。分析如下:

1. 当Server发送FIN标识时,用ACK=323,SEQ=138答复手机;  (因为是TCP信令,Server期望看到ACK=139的报文)
2. 手机接收到这个包后,用ACK=139,SEQ=323答复;(此报文不携带内容,所以手机期望ACK=323的报文回应)。一旦回复了这个报文,在Server就只能接受数据,而不能发送任何数据了。
3. 紧接着,手机再次发出GET请求,该报文发给Server后,由于Server侧TCP状态的原因,肯定不能递给上层应用程序了,所以该请求是无效的;
4. 再接着,手机发出FIN标识包,要关闭自己的TCP连接,用SEQ=645,ACK=139来发送;(由于是TCP信令,期望Server用ACK=646来答复自己)。 从此处的包可以看出手机发出GET的内容长度为322字节;
5. Server用ACK=646来答复手机。这样手机的TCP发送功能也就关闭了。

可以得出,手机已经知道了Server端已不能处理请求,但仍然发送GET服务请求,整个过程中TCP序例号完全吻合,这是纯应用层与操作系统的问题,与GB无任何关系。建议看下是不是与应用软件的设置相关?另外,看看同样的应用在不同类型的手机上(如android、iphone、wp、symbian)会不会呈现相同的情况。

使用道具 举报

Rank: 2Rank: 2

5#
发表于 2013-9-27 16:44:50 |只看该作者
LOG放上去了,tcp.stream eq 40   ,冒昧的问下,不同系统的手机比如安卓,ios,塞班,都是不同的程序,但访问的资源URI这些应该都一样吧?

点评

爱卫生  访问的URI是一样,但不同的操作系统对于协议的处理可能不一样。因为是不同的语言不同的人开发的。比如半关状态下是否发get的处理。  发表于 2013-9-28 00:31:35
爱卫生  我的个人观点哦,这个应该是手机的行为导致的,但根据TCP规范,并不能说手机违反规范了。下行单方面关闭应该还是可以发上行的get的。比较麻烦。  发表于 2013-9-28 00:30:37

使用道具 举报

Rank: 3Rank: 3Rank: 3

乐于助人

6#
发表于 2013-9-28 21:21:50 |只看该作者
仔细看了下抓包,的确看不出Gb有什么问题。只能查查终端本身的原因了。

使用道具 举报

Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6

7#
发表于 2014-1-15 12:59:18 |只看该作者
问题很简单:

首先,你需要更新一下wireshark,在我的Wireshark显示那个200 OK [frame478] 是“Malformed Packet”,这才是终端重新发起GET的原因。

其次,检查两次GET的URL也完全一致,确认的确是重新请求资源,[frame 476, frame 552]

最后,根据个人经验,虽然一次TCP允许多次GET,但实际上看到的基本上都是因错误导致的重新请求,不知道大家是否有看到不同URL的GET在同一个TCP Link中?

附件: 你需要登录才可以下载或查看附件。没有帐号?立即注册

使用道具 举报

Rank: 1

8#
发表于 2014-2-12 10:55:26 |只看该作者
kinghighland 发表于 2014-1-15 12:59
问题很简单:

首先,你需要更新一下wireshark,在我的Wireshark显示那个200 OK [frame478] 是“Malforme ...

为什么我用新版wireshark 1.11.0,frame478 却是没有问题的?
提示是:
478 2013-09-22 17:19:36.298631 111.1.57.21 10.157.181.201 HTTP 302 HTTP/1.1 200 OK  (audio/x-ms-wma)

使用道具 举报

Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6Rank: 6

9#
发表于 2014-2-12 16:29:56 |只看该作者
看来不是版本问题,你的版本比我的新多了

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

站长邮箱|Archiver|51学通信 ( 粤ICP备11025688 )

GMT+8, 2024-5-4 17:31 , Processed in 0.033059 second(s), 14 queries .

Powered by Discuz! X2

© 2001-2011 Comsenz Inc.

回顶部