您的位置:首页 > 理论基础 > 计算机网络

TCP三次握手,数据传输,四次挥手

2016-01-16 17:04 666 查看
[b]TCP包结构[/b]

  一个TCP包结构如下:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define HI "hi,can you see me?"

int main ( int argc, char *argv[] )
{
int ret;
int socketfd,acfd;
int socklen;
struct sockaddr_in hostaddr;
char buf[1024];

socketfd = socket(AF_INET, SOCK_STREAM, 0);
if ( socketfd < 0 )
{
perror("socket");
return -1;
}

memset((void *)&hostaddr, 0, sizeof(hostaddr));
hostaddr.sin_family = AF_INET;
hostaddr.sin_port = htons(6666);
hostaddr.sin_addr.s_addr = htonl(INADDR_ANY);

socklen = sizeof(struct sockaddr);
acfd = connect(socketfd, (struct sockaddr *)&hostaddr, sizeof(hostaddr));
if ( acfd < 0 )
{
perror("connect");
close(socketfd);
return -1;
}

write(socketfd, HI, sizeof(HI));

//memset(buf, 0x0, sizeof(buf));
//read(socketfd, buf, sizeof(buf));
//printf("%s\n",buf);

close(socketfd);
return 0;
}


View Code

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



  这就是TCP三次握手的3个包,TCP的握手是发生在client端进行connect时。

  对于握手包的Sequence number和Acknowledgment number我理解为三次握手的包序。这里有RFC 793的解释:

  Sequence Number: 32 bits The sequence number of the first data octet in this segment (except when SYN is present). If SYN is present the sequence number is the initial sequence number (ISN) and the first data octet is ISN+1.

  Acknowledgment Number: 32 bits If the ACK control bit is set this field contains the value of the next sequence number the sender of the segment is expecting to receive. Once a connection is established this is always sent.

  第一次握手:

    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被置位,没有数据部分。

[b]为什么要三次握手[/b]

  结合网上搜索,我觉得这是由于TCP是可靠的全双工的传输协议。首先,为什么要握手?因为需要确保可靠。为什么要3次,因为3次是理论上确保全双工握手成功的最少次数。对于单工,确保一次通信可以需要:1发送方把数据发送出去(SYN),2接收方回应发送方接收成功(ACK),这样形成了一个闭环。看看三次握手怎么做的:

  第一次: CLIENT----syn----->SERVER

  第二次: SERVER----ack,syn---->CLIENT

  第三次: CLIENT----ack----->SERVER

  这样,从client---->server, server---->client各自通过一次syn,ack形成闭环,理论上形成了一个近似可靠的通信。为什么说是近似可靠?因为完全可靠的通信是不存在的,见谢希仁<<计算机网络>>里面讲的红团蓝团问题。

[b]TCP数据的传输[/b]

  握手成功后,开始传输第一个分节的数据,一次数据的传输需要2个TCP包。数据发送包,接收方应答包。

  1.Client---data--->Server:

  


  2.Server---ack--->Client



[b]TCP的四次挥手[/b]

    四次挥手的时序



  一般来说,网络编程的CS模型中,服务端可以认为是一直不退出的,并且它是被动的一放,因此一般需要断开连接都是由客户端主动提出。

  类似于TCP的三次握手,四次挥手的四步:

    Client---fin,ack--->Server

    Server---ack---->Clinet

    Server---fin,ack--->Client

    Client----ack----->Server

  先把2次发送FIN的包中的ACK(未着色的)忽略,因为TCP建立连接后ACK必须置位。类似于三次握手的分析,一对FIN--ACK包的往来,形成一个闭环,保证了单侧通信的可靠。对比于三次握手,为什么不把四次挥手中间2个包合并呢?它们都是S-->C为什么要单独拆分来发送呢?注意到FIN的意义:表示这个方向的带数据的包传输已经完成,即发送FIN包的端没有带数据的包过来了,需要释放这个方向的连接。。那么接收到FIN包的这一方虽然不再接收对端的带数据的包,但是它仍然可以发带数据的包过去。

  以后补充

  /article/1610798.html

  /article/1395085.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: