码迷,mamicode.com
首页 > 其他好文 > 详细

TCP三次握手及数据传输分析

时间:2016-01-16 19:19:05      阅读:218      评论:0      收藏:0      [点我收藏+]

标签:

  • TCP包结构

  一个TCP包结构如下:

技术分享

  一个TCP包主要由TCP包头和数据部分组成,包头固定部分为20字节,选项和数据部分根据实际情况设置为4N(N可以为0)字节。

  1.16bit源端口和目的端口号,它可以确认数据的传输方向(暂不考虑更底层的包)

  2.32bit序号,它是为TCP包中数据部分进行编号的部分。假设要发送的数据有100M,由于受MSS( Maximum Segment Size 最大报文段长度)限制,一个TCP包是不可能传输完这100M的数据,于是需要将数据拆分,为了确保拆分传输后的数据能在接收端正确的拼接,就需要对每个拆分的数据包进行编号来传输。这样,这个32位的序号指的就是本包数据部分第一个字节是这个100M数据中的第多少个字节。例如:假设发送第一个包时,先取出这100M数据的前面1024个字节发送,这时这个包中32位序号就是1,然后取下一个1024字节传输,这个时候的数据部分的第一个字节是这100M数据的第1025个字节,所以这第二TCP包中32位的序列号就应该为1025。当序号超过2^32时,进行一个轮回,重新从0开始计数。

  3.32bit确认序号,和上面的32位序号类似,只不过它指的是期望收到的下一个包的数据部分的编号。

  4.4bit首部长度,单位为4字节,指的是一个TCP包中除去数据部分的长度,也就是包头固定部分+选项部分的长度,2^4 -1 = 15, 15*4字节=60字节,即包头固定部分为20字节,选项最多可以为40字节。

  5.标识位:

    URG:.........

    ACK:TCP包的应答位

    PSH:TCP包中有数据需要尽快传递给应用层使用,而不是将数据进行缓冲,等到缓冲区满了再投递给应用层。

    RST:..........

    SYN:TCP包的同步位

    FIN:表示数据传输已经完成,释放连接。

 

  • TCP三次握手

  TCP三次握手过程:

  技术分享

  测试代码,server端:

技术分享
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <sys/types.h>
 4 #include <sys/socket.h>
 5 #include <netinet/in.h>
 6 
 7 int main ( int argc, char *argv[] )
 8 {   
 9     int ret,rn;
10     int socketfd,acfd;
11     int socklen;
12     char buf[1024];
13     
14     struct sockaddr_in hostaddr;
15     struct sockaddr_in clientaddr;
16     
17     socketfd = socket(AF_INET, SOCK_STREAM, 0);
18     if ( socketfd < 0 )
19     {
20         perror("socket");
21         return -1;
22     }
23 
24     memset((void *)&hostaddr, 0, sizeof(hostaddr));
25     hostaddr.sin_family = AF_INET;  
26     hostaddr.sin_port = htons(6666);  
27     hostaddr.sin_addr.s_addr = htonl(INADDR_ANY);
28     
29     ret = bind(socketfd, (struct sockaddr *)&hostaddr, sizeof(hostaddr));
30     if ( ret < 0 )
31     {
32         perror("bind");
33         close(socketfd);
34         return -1;
35     }
36 
37     ret = listen(socketfd, 5);
38     if ( ret < 0 )
39     {
40         perror("listen");
41         close(socketfd);
42         return -1;
43     }
44 
45     socklen = sizeof(struct sockaddr);
46     acfd = accept(socketfd, (struct sockaddr *)&clientaddr, &socklen);
47     if ( acfd < 0 )
48     {
49         perror("accept");
50         close(socketfd);
51         return -1;
52     }
53     
54     while (1)
55     {
56         memset(buf, 0x0, sizeof(buf));
57         rn = read(acfd, buf, sizeof(buf));
58         if ( rn < 0 )
59         {
60             perror("read");
61             continue;
62         }
63         printf("%s\n",buf);
64     }
65     close(socketfd);
66     return 0;
67 } 
View Code

  client端:

技术分享
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <unistd.h>
 4 #include <sys/types.h>
 5 #include <sys/socket.h>
 6 #include <netinet/in.h>
 7 
 8 #define REQURE "hi,can you see me?"
 9 
10 int main ( int argc, char *argv[] )
11 {   
12     int ret;
13     int socketfd,acfd;
14     int socklen;
15     struct sockaddr_in hostaddr;
16     
17     socketfd = socket(AF_INET, SOCK_STREAM, 0);
18     if ( socketfd < 0 )
19     {
20         perror("socket");
21         return -1;
22     }
23 
24     memset((void *)&hostaddr, 0, sizeof(hostaddr));
25     hostaddr.sin_family = AF_INET;  
26     hostaddr.sin_port = htons(6666);  
27     hostaddr.sin_addr.s_addr = htonl(INADDR_ANY);
28     
29     socklen = sizeof(struct sockaddr);
30     acfd = connect(socketfd, (struct sockaddr *)&hostaddr, sizeof(hostaddr));
31     if ( acfd < 0 )
32     {
33         perror("connect");
34         close(socketfd);
35         return -1;
36     }
37     
38     while (1)
39     {
40         sleep(10);
41         write(socketfd, REQURE, sizeof(REQURE));
42     }
43     close(socketfd);
44     return 0;
45 } 
View Code

   这是CS间一对一的连接方式,一发一收。先运行server端,在accept下一行下断点,再运行client端,在connet的下一行下断点,使用wireshark抓包,过滤端口为6666的tcp包 tcp.port == 6666 ,运行,再断点处停下来时,可以看到抓到了3个包:

技术分享

 

  这就是TCP三次握手的3个包,TCP的握手是发生在client端进行connect时。对于握手包的Sequence number和Acknowledgment number我理解为三次握手的包序。

  第一次握手:

    client:"server,我要找你了!(SYN == 1),这是我第一次和你说话(Seq num == 0)" ,TCP包如下:

技术分享

    可以看到Source port:33335,Destination port:6666,说明是C--->S这个方向传输的,Sequence为0,SYN被置位,没有数据部分。

  第二次握手:

    server:"client我听到你叫我了(ACK = = 1),你听到我的回应了吗(SYN == 1)?,这是我第一次和你说话(Seq num == 0),我等你第二次和我说话(Ack num == 1)",TCP包如下:

技术分享

    可以看到Source port:6666,Destination port:33335,说明是S--->C这个方向传输的,Sequence num为0,Ack num为 1,SYN,ACK被置位,没有数据部分。

  第三次握手:

    clinet:"server,知道你听到我了(ACK ==  1),我们可以开聊了,这是我第二次和你说话(Seq num == 1),我等你和我第二次说话(Ack num == 1)"

    技术分享

    可以看到Source port:33335,Destination port:6666,说明是C--->S这个方向传输的,Sequence num为1,Ack num为 1,ACK被置位,没有数据部分。

 

TCP三次握手及数据传输分析

标签:

原文地址:http://www.cnblogs.com/thammer/p/5135827.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!