通过TCP回射服务器分析TCP协议基本流程(一)
2014-10-27 16:54
162 查看
本文将对一个简单的TCP回射服务器和客户端进行抓包,从而分析一次成功而理想TCP会话的基本流程,多次不成功或与预期不一致的抓包结果将在下篇博文进行分析
本文程序编译环境为:
Linux version 3.16.4-1-ARCH
gcc version 4.9.1 20140903 (prerelease)
Glibc 2.18
服务器代码如下:
客户端代码如下:
首先展示抓包结果,这是一个完全符合书本理论的理想状况,下篇博客将会通过调试器等手段制造非理想状况,进而分析其行为,因此不对TCP包结构进行讨论,TCP包的WIN字段用于滑动窗口的控制,本文暂不涉及
![](http://images.cnblogs.com/cnblogs_com/current/613723/o_successpkg.png)
首先:一次TCP会话的基本流程应该分为以下三步
与对方套接字建立连接
与对方套接字进行数据交换
断开与对方套接字的连接
下面即对抓包结果进行分析,从而分析出这三个步骤中实际发生了什么,需要说明的是,抓包得到的No序号和TCP包中seq和ack的序号不是一个东西,由于我使用SSH连接了测试机进行控制,因此抓包软件连同SSH的数据包一并抓取,造成与我们测试内容相关的数据包序号不连续,不过这并不影响我们的分析和理解
107号数据包,客户端发往服务端,SYN置位,表面消息类型为SYN,即同步消息,Seq=0,这是客户端首次请求连接时所产生的消息
seq的含义为“客户端发往服务端的seq为0,长度为0的数据包,等待服务端确认收到,并请求客户端发往服务端发送seq为1的数据包”
109号数据包,服务器收到了连接请求SYN,做出应答,应答消息的数据包中,SYN,ACK置位,即消息类型为SYN+ACK,Seq=0,Ack=1
Seq含义为“服务端将向客户端发送seq为0长度为0的数据包,等待客户端确认收到,并请求发送服务器发往客户端的seq为1的数据包”
Ack的含义为“服务端已收到客户端发往服务端的seq为0长度为0的数据包,客户端可以发送seq为1的数据包”
需要注意的是,在上文中我采用了“从a发往b的seq为n的长度为k数据包”,非常啰嗦,其原因在于
seq与ack值的增长并非是按照数据包数量增长的,其增量为传输的数据字节数,即LEN,其增长规则为:ack = seq + len
SYN消息和FIN消息会使seq增长1
与书本中的描述不同,书本描述中SYN包的seq和SYN+ACK包的seq不相同,造成一种“客户端套接字和服务端套接字发数据包seq是在一个线性空间中”的错觉,此处抓包结果已经展示出,客户端的seq和服务端的seq是独立位于两个线性空间中,互不干涉,没有查看TCP协议的标准文档,此处暂时存疑
110号数据包,客户端收到了服务端发来的SYN+ACK消息,做出ACK应答,seq为1,ack为1,含义可以参照上文,
107,109,110号数据包即TCP会话基本流程的第一步:与对方套接字建立连接,这个过程一共进行了三次数据包的传递,也就是俗称的三次握手
111号数据包由客户端发往服务端,PSH,ACK置位,seq=1,ack=1,len=12
112号数据包由服务端发往客户端,ACK置位,seq=1,ack=13,可以看出,服务端收到了客户端发来的seq为1,长度为12的数据包,并通知客户端可以发送seq为13的数据包,从而证实了,数据包seq的增量取决于传输的字节数
113号数据包由服务端发往客户端,即回射的数据,PSH,ACK置位,seq=1,ack=13,Len=12,
从这个包可以得出两点
在没有收到请求的数据包时,tcp会话的某一方会重新请求该数据包
tcp会话的某一方不会做出“某个数据包已经请求,以后将会收到”的假设
回顾之前的包,不难发现,所有的tcp包中都有seq和ack两个值,因此可以猜想,seq和ack是面向连接的TCP会话可靠性的重要保证和依赖,暂时没有查询标准文档,因此这儿仅作猜想
115号包,由客户端发往服务端,ACK置位,seq=13,ack=13,表明客户端成功接收了服务端回射的数据
111,112,113,115四个数据包展示了客户端服务端进行一次数据交换的过程,两个来回,并根据实际的业务逻辑而变化,这就是TCP会话中的第二步:与对方套接字进行数据交换
119号包,客户端发往服务端,FIN,ACK置位,表明即将断开连接,等待服务端回应
121号包,服务端发往客户端,ACK置位,对客户端的FIN请求做出了回应
123号包,服务端发往客户端,FIN,ACK置位,表明服务端也将断开和客户端的连接,等待客户端回应
124号包,客户端发往服务端,ACK置位,对服务端的断开请求进行回应,并真正断开(这么说并不确切,不过本文不进行深究)
119,121,123,124号包实现了一次TCP会话中的第三步:断开与对方套接字的连接,这个过程经历了四次数据包的传递,也就是俗称的四次挥手,至此,一次TCP会话成功完成,下篇博文将会讨论一次TCP会话中的状态转移,并分析一些和本文不同的抓包结果
本文程序编译环境为:
Linux version 3.16.4-1-ARCH
gcc version 4.9.1 20140903 (prerelease)
Glibc 2.18
服务器代码如下:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define ERR_EXIT(exp) \ do\ {\ perror(exp);\ exit(EXIT_FAILURE);\ }while(0) #define BUFSIZE 1024 int main(int argc, char *argv[]) { if(argc != 2) ERR_EXIT("Usage: a.out <port>"); int server_sock; int client_sock; struct sockaddr_in server_addr; struct sockaddr_in client_addr; socklen_t server_len; socklen_t client_len; server_sock = socket(PF_INET, SOCK_STREAM, 0); if(server_sock == -1) ERR_EXIT("socket"); memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = INADDR_ANY; server_addr.sin_port = htons(atoi(argv[1])); server_len = sizeof(server_addr); client_len = sizeof(client_addr); if(bind(server_sock, (struct sockaddr*)&server_addr, server_len) == -1) ERR_EXIT("bind"); if(listen(server_sock, 5) == -1) ERR_EXIT("listen"); client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_len); if(client_sock == -1) ERR_EXIT("accept"); char buffer[BUFSIZE] = {0}; read(client_sock, buffer, BUFSIZE); write(client_sock, buffer, strlen(buffer)); sleep(3); close(client_sock); close(server_sock); return 0; }
客户端代码如下:
#include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #define ERR_EXIT(exp) \ do\ {\ perror(exp);\ exit(EXIT_FAILURE);\ }while(0) #define BUFSIZE 1024 int main(int argc, char *argv[]) { if(argc != 3) ERR_EXIT("Usage: a.out <server_ip> <port>"); int server_sock; struct sockaddr_in server_addr; socklen_t server_len; server_sock = socket(PF_INET, SOCK_STREAM, 0); if(server_sock == -1) ERR_EXIT("socket"); server_addr.sin_family = AF_INET; server_addr.sin_addr.s_addr = inet_addr(argv[1]); server_addr.sin_port = htons(atoi(argv[2])); server_len = sizeof(server_addr); if(connect(server_sock, (struct sockaddr*)&server_addr, server_len) == -1) ERR_EXIT("connect"); char buffer[BUFSIZE] = "Hello World!"; write(server_sock, buffer, strlen(buffer)); memset(buffer, 0, BUFSIZE); read(server_sock, buffer, BUFSIZE); printf("%s\n", buffer); sleep(1); close(server_sock); return 0; }
首先展示抓包结果,这是一个完全符合书本理论的理想状况,下篇博客将会通过调试器等手段制造非理想状况,进而分析其行为,因此不对TCP包结构进行讨论,TCP包的WIN字段用于滑动窗口的控制,本文暂不涉及
![](http://images.cnblogs.com/cnblogs_com/current/613723/o_successpkg.png)
首先:一次TCP会话的基本流程应该分为以下三步
与对方套接字建立连接
与对方套接字进行数据交换
断开与对方套接字的连接
下面即对抓包结果进行分析,从而分析出这三个步骤中实际发生了什么,需要说明的是,抓包得到的No序号和TCP包中seq和ack的序号不是一个东西,由于我使用SSH连接了测试机进行控制,因此抓包软件连同SSH的数据包一并抓取,造成与我们测试内容相关的数据包序号不连续,不过这并不影响我们的分析和理解
107号数据包,客户端发往服务端,SYN置位,表面消息类型为SYN,即同步消息,Seq=0,这是客户端首次请求连接时所产生的消息
seq的含义为“客户端发往服务端的seq为0,长度为0的数据包,等待服务端确认收到,并请求客户端发往服务端发送seq为1的数据包”
109号数据包,服务器收到了连接请求SYN,做出应答,应答消息的数据包中,SYN,ACK置位,即消息类型为SYN+ACK,Seq=0,Ack=1
Seq含义为“服务端将向客户端发送seq为0长度为0的数据包,等待客户端确认收到,并请求发送服务器发往客户端的seq为1的数据包”
Ack的含义为“服务端已收到客户端发往服务端的seq为0长度为0的数据包,客户端可以发送seq为1的数据包”
需要注意的是,在上文中我采用了“从a发往b的seq为n的长度为k数据包”,非常啰嗦,其原因在于
seq与ack值的增长并非是按照数据包数量增长的,其增量为传输的数据字节数,即LEN,其增长规则为:ack = seq + len
SYN消息和FIN消息会使seq增长1
与书本中的描述不同,书本描述中SYN包的seq和SYN+ACK包的seq不相同,造成一种“客户端套接字和服务端套接字发数据包seq是在一个线性空间中”的错觉,此处抓包结果已经展示出,客户端的seq和服务端的seq是独立位于两个线性空间中,互不干涉,没有查看TCP协议的标准文档,此处暂时存疑
110号数据包,客户端收到了服务端发来的SYN+ACK消息,做出ACK应答,seq为1,ack为1,含义可以参照上文,
107,109,110号数据包即TCP会话基本流程的第一步:与对方套接字建立连接,这个过程一共进行了三次数据包的传递,也就是俗称的三次握手
111号数据包由客户端发往服务端,PSH,ACK置位,seq=1,ack=1,len=12
112号数据包由服务端发往客户端,ACK置位,seq=1,ack=13,可以看出,服务端收到了客户端发来的seq为1,长度为12的数据包,并通知客户端可以发送seq为13的数据包,从而证实了,数据包seq的增量取决于传输的字节数
113号数据包由服务端发往客户端,即回射的数据,PSH,ACK置位,seq=1,ack=13,Len=12,
从这个包可以得出两点
在没有收到请求的数据包时,tcp会话的某一方会重新请求该数据包
tcp会话的某一方不会做出“某个数据包已经请求,以后将会收到”的假设
回顾之前的包,不难发现,所有的tcp包中都有seq和ack两个值,因此可以猜想,seq和ack是面向连接的TCP会话可靠性的重要保证和依赖,暂时没有查询标准文档,因此这儿仅作猜想
115号包,由客户端发往服务端,ACK置位,seq=13,ack=13,表明客户端成功接收了服务端回射的数据
111,112,113,115四个数据包展示了客户端服务端进行一次数据交换的过程,两个来回,并根据实际的业务逻辑而变化,这就是TCP会话中的第二步:与对方套接字进行数据交换
119号包,客户端发往服务端,FIN,ACK置位,表明即将断开连接,等待服务端回应
121号包,服务端发往客户端,ACK置位,对客户端的FIN请求做出了回应
123号包,服务端发往客户端,FIN,ACK置位,表明服务端也将断开和客户端的连接,等待客户端回应
124号包,客户端发往服务端,ACK置位,对服务端的断开请求进行回应,并真正断开(这么说并不确切,不过本文不进行深究)
119,121,123,124号包实现了一次TCP会话中的第三步:断开与对方套接字的连接,这个过程经历了四次数据包的传递,也就是俗称的四次挥手,至此,一次TCP会话成功完成,下篇博文将会讨论一次TCP会话中的状态转移,并分析一些和本文不同的抓包结果
相关文章推荐
- select实现tcp并发服务器的基本框架流程
- Android逆向分析学习与研究(2)————通过“轮盘赌”简要看看smali的基本流程控制
- ASP.NET通过DSO访问分析服务器的权限问题
- MonoRail学习笔记四:MonoRail基本流程分析
- 通过TCP/IP方式连接 “不能上到 mysqL 服务器连接 ”解决方法
- 无法分析从服务器收到的消息。之所以出现此错误,常见的原因是: 在通过调用 Response.Write() 修改响应时,将启用响应筛选器、HttpModule 或服务器跟踪
- NAT分析(内网用户通过域名访问服务器)
- 服务器和客户机通过TCP/IP三次握手建立一个连接
- java 通过 socket 实现 服务器和客户端的通信 TCP
- android中通过拨号键打开contacts相关界面的流程分析
- RTSP服务器处理客户端点播的基本流程
- webmail和lotus notes无法登录或连接服务器分析流程
- 无法分析从服务器收到的消息。之所以出现此错误,常见的原因是: 在通过调用 Response.Write() 修改响应时,将启用响应筛选器、HttpModule 或服务器跟踪。
- [转]RTSP服务器处理客户端点播的基本流程
- 无法分析从服务器收到的消息。之所以出现此错误,常见的原因是: 在通过调用 Response.Write() 修改响应时,将启用响应筛选器、HttpModule 或服务器跟踪。
- live555库的rtsp服务器源码分析总结,流程详解RTSPServer
- MonoRail学习笔记四:MonoRail基本流程分析
- 如何通过分析Web服务器记录查找黑客攻击的踪迹?
- 无法分析从服务器收到的消息。之所以出现此错误,常见的原因是: 在通过调用 Response.Write() 修改响
- live555库的rtsp服务器源码分析总结,流程详解RTSPServer