深入理解Tcp协议及其源代码
一、TCP的三次握手
TCP窗口大小
信息。第一次:客户端发送SYN报文,主动发起连接请求,SYN=1,seq=x
第二次:服务端收到SYN报文,回复ACK+SYN报文,SYN=1, ACK=1,seq=y ,ack=x+1
第三次:客户端收到服务端ACK,回复ACK报文,SYN=1, ACK=1,seq=x+1 ,ack=y+1,连接建立
二、实验过程
socket的出现只是可以更方便的使用TCP/IP协议栈而已,其对TCP/IP进行了抽象,形成了几个最基本的函数接口。比如create,listen,accept,connect,read和write。上次实验中我们已经知道在linux中网络通信服务器端socket、bind、listen、accept实际调用封装的系统调用分别是__sys_socket、__sys_bind、_sys_listen、_sys_accept4.......
这一次深入内核探索tcp三次握手的具体细节:
我们都知道服务器客户端实现通信是服务器处于运行态,等待客户端的连接请求,服务器收到客户端连接请求之后,就为客户端分配资源,从而建立起连接,开始收发信息工作。其中tcp实现三次握手来建立连接。
为什么要进行三次握手呢?
我们都知道前两次一定是必须的——因为需要同步序号,服务器为客户端分配资源等一些初始化工作,那为什么又要进行第三次客户端向服务器发送ack包呢?
一句话,主要防止已经失效的连接请求报文突然又传送到了服务器,从而产生错误。
如果使用的是两次握手建立连接,假设有这样一种场景,客户端发送了第一个请求连接并且没有丢失,只是因为在网络结点中滞留的时间太长了,由于TCP的客户端迟迟没有收到确认报文,以为服务器没有收到,此时重新向服务器发送这条报文,此后客户端和服务器经过两次握手完成连接,传输数据,然后关闭连接。此时此前滞留的那一次请求连接,网络通畅了到达了服务器,这个报文本该是失效的,但是,两次握手的机制将会让客户端和服务器再次建立连接,这将导致不必要的错误和资源的浪费。
如果采用的是三次握手,就算是那一次失效的报文传送过来了,服务端接受到了那条失效报文并且回复了确认报文,但是客户端不会再次发出确认。由于服务器收不到确认,就知道客户端并没有请求连接,此时就会回收为客户端的准备资源。这也是防止SYN洪泛攻击的原理。
那么三次握手对应我们socket的时机又是在哪里?
显然是客户端connect以及服务器段accept后。
当连接建立后,执行send()及rev()进行数据通信。
知道TCP建立连接的过程,接下来我们来深入探究一下它的初始化和套接字初始化过程。在文件/net/tcp /下找到accpet函数定义发现它最终调用了__sys_accept4,同时connect函数调用了__sys_connect函数。
int __sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen) { struct socket *sock; struct sockaddr_storage address; int err, fput_needed; ? sock = sockfd_lookup_light(fd, &err, &fput_needed); if (!sock) goto out; err = move_addr_to_kernel(uservaddr, addrlen, &address); if (err < 0) goto out_put; ? err = security_socket_connect(sock, (struct sockaddr *)&address, addrlen); if (err) goto out_put; ? err = sock->ops->connect(sock, (struct sockaddr *)&address, addrlen, sock->file->f_flags); out_put: fput_light(sock->file, fput_needed); out: return err; }
可以看到其中是通过调用 sock->ops->connect实现,查看sock->ops->connect函数实现
gdb调试
未完待续.....