TCP连接三次握手
(refer to: http://blog.csdn.net/firefoxbug/article/details/7832996)
TCP是面向连接的协议,面向连接的意思就是在连接的基础上实现数据的传输。TCP面向连接保证了它在通信过程中的可靠性。
TCP头部是20个字节,详细的报文格式和各个字段的解释可以看下面:
在TCP通信之前,建立连接的过程被称为三次握手,下面是wireshark抓出来的图。
1.第一次握手:客户端发送SYN标志,序列号seq(随机生成,图中序列号是0是wireshark做了相对处理),源端口随机生成,目标端口5000(程序决定),
头长度40字节是因为包含了可选字段。
2.第二次握手:服务端发回客户端,ACK标识同意接收连接,此时从客户端到服务端单向连接建立,SYN标识服务端向客户端建立连接,同时标识了序列号
(同上)对于ack(区别上面的ACK(1bit)标识,ack是4bytes)则是上一个包的seq+1,告诉客户端下一个包的seq。
3.第三次握手:客户端发回服务端,ACK标识同意接收服务端的连接,此致双向连接都建立好了。这个包的seq就是上个包的ack,再者这里的ack就是下个
包的seq。
socket通信机制:
服务端 客户端
socket socket
bind
listen connect
accept(阻塞)
read/write write/read
close close
那么对于tcp三次握手是在程序的什么时候建立的呢?现在我把客户端bind之后跑到listen之前(未执行listen),然后从客户端一旦执行connect,立刻
被服务端RST了。这里可以说明是由connect来发出tcp三次握手的第一个SYN包,wireshark可以抓出来。
现在把客户端往下走,调用listen,但是没有调用accept,然后客户端重新调用connect,这时候wireshark就马上出现了tcp三次握手建立成功。这个时候
已经有一个成功建立连接的套接字在TCP/IP协议栈的队列里。
建立连接之后,调用accept函数马上就返回的,accept函数的作用就是从TCP/IP协议栈队列中取出一个成功建立连接的套接字,用于和用户层交互。accept
是阻塞型的,如果accept发现队列里是空的,就会一直阻塞,直到出现成功连接的套解字。
总计上面的,整个流程是这样的:
服务端 客户端
socket socket
bind
listen(端口和IP都已经确定) connect(发出SYN包)
(<=============tcp连接三次握手=========>)
accept(取出队列中的套解字)
close close