Socket原理探索
1、网络进程通信之socket
在使用TCP/IP协议族进行网络通信的过程中,网络层的IP地址可以唯一标识一台网络主机,而传输层的协议+端口可以唯一标识主机中的应用程序进程,利用这样的三元组合(IP地址,协议,端口)就可以在网络中唯一标识网络中的进程,从而为进程在网络中的通信建立了基石。
TCP/IP协议族为网络通信提供了编程接口,Socket正是其代表,Socket起源于Unix,在Unix一切皆文件哲学的思想下,socket是一种"打开—读/写—关闭"模式的实现,服务器和客户端各自维护一个"文件",socket可以视为这个文件的句柄或者称之为文件描述符,在建立连接打开后,可以向自己文件写入内容供对方读取或者读取对方内容,通讯结束时关闭文件。
socket是在应用层和传输层之间的一个抽象层,它把TCP/IP层复杂的操作抽象为几个简单的接口供应用层调用已实现进程在网络中通信。socket在通信模型中的角色与位置如下图:
2、socket如何进行通信
建立socket通信需要用到五大元素(协议,源IP,源端口,目的IP,目的端口),只要保证这样的五元组合唯一便能建立socket通信连接。
其通信建立的过程大致为:1)服务端初始化socket,与端口(例如8080)绑定(bind),端口监听(listen),调用accept等待客户端连接。2)客户端初始化socket,客户端随机分配一个端口(例如6688)发起对服务端监听端口(8080)的连接(connect),服务端IP层收到请求之后,根据具体协议类型交由传输层协议栈处理,传输层再交由socket层处理,socket层以监听端口(8080)作为服务端端口建立与客户端的连接,创建新的socket实例(该实例包含客户端IP,客户端端口6688,服务端端口8080,服务端IP)用于标识此次连接的服务端句柄,并将其放进连接队列(连接队列的大小是由服务端listen之时指定的,一旦连接数达到限制,将会拒绝或者延迟新的连接请求)。
连接建立之后,两端可以通过各自的终端句柄socket实例(因为其包含有socket通信的五元组合)进行数据传输(客户端仍然向服务端的8080端口发送数据),目的端主机的传输层接收到数据之后,仍然交由socket层处理,socket层根据源/宿对准确的分辨出数据包与socket实例的归属关系。通信图示如下:
3、socket建立/关闭连接的三次握手与四次挥手
建立连接的三次握手如下图:
这三次握手详细流程大致为:
- 客户端socket对象connect调用之后进行阻塞,此过程发送了一个SYN(同步序列编号Synchronize Sequence Numbers)。
- 服务端监听到连接请求,如果请求被允许,便向客户端发送对收到的SYN的确认包ACK,同时自己也会发送一个SYN。此时accept仍然处于阻塞状态。
- 客户端收到SYN+ACK之后,connect返回,并向服务端发送ACK确认包,服务端收到之后,accept返回,连接建立成功。
关闭连接的四次挥手如下图:
这四次握手详细流程大致为:
- 某端首先调用close主动关闭连接,这时TCP向另一端发送一个FIN M包。
- 另一端的read返回0表面收到了FIN段,就知道另一端关闭了连接,那么首先发送一个对FIN的确认包ACK
- 发送确认包之后,也调用close关闭连接,从而导致它的TCP也会发送一个FIN N包。
- 接收到这个FIN的源端TCP最后发出确认包ACK,完成四次握手。
注意:任何一方调用close()后,连接的两个传输方向都关闭,不能再发送数据了。如果一方调用shutdown()则连接处于半关闭状态,仍可接收对方发来的数据。