[底层原理]Socket 究竟是什么? 为啥网络离不开 Socket?

前言

一说到网络,大家必然会想到 TCP、UDP、Http、三握四挥等,但是一说 Socket,大家可能会有点模糊了,只知道网络中会用到,但是 Socket 究竟是什么? 套接字又是啥?为啥网络离不开 Socket?

Socket 是什么?

Socket 其实就是套接字,大部分人对于 Socket 的理解就是它可以实现一个简单的网络通信,但是它「具体解决了哪些问题?有什么实际的作用?为什么会有一个 Socket 出现?」

Socket 其实是在「应用层与传输层之间的一个产物」,它把传输层的很多复杂操作封装成一些简单的接口,来让应用层调用以此来实现进程在网络中的通信,Socket 是对端口通信开发的工具,它要更底层一些。

Socket 其实类似于一台洗碗机,它的功能就是洗碗(网络通信),如果没有它,你可能需要自己手动去洗碗(手动调用传输层、应用层之间的各个 api),但是有了它你只需要点击开关、调整时长就行了(封装了 api),你可以不需要它,但是如果没有它,洗碗(应用层与传输层之间的交互)将变得非常繁琐。

​一次完整的网络通信必不可少的会经过物理传输层的网线和网卡,网络传输层的 IP 协议可以知道要将数据传送给哪台机器,但是在计算机系统中会运行不同进程,那要如何把「网卡中的网络数据识别出来是给哪个进程的」,这其实就是 Socket 设计的想解决的一点了。

Socket 是「对 TCP/IP 或者 UDP/IP 协议的封装」,Socket 本身其实就是一个调用接口。通过这个接口我们在开发网络应用程序的时候,就可以不用关心底层是怎么实现的,减轻开发的难度。

Socket 运行流程

基于 TCP

​Server

  • socket():表示创建一个 socket,底层会生成一个文件描述符,用来表示该 socket

  • bind():用来绑定服务的端口,地址,这里一般都是以固定的为主,因为在客户端连接的时候需要指定

  • listen():当绑定完成之后,listen 就会监听这个端口的数据包

  • accept():相当于一个开关,表示我准备好了,可以接受请求了,但是这里会一直阻塞,直到客户端连接成功

  • read():读取客户端发送过来的内容

  • write():客户端写入要返回的数据

  • close():断开连接,「四次挥手」

Client

  • socket():表示创建一个 socket,底层会生成一个文件描述符,用来表示该 socket

  • connet():表示与指定地址进行连接,在此之前,会随机创建自己的端口,tcp 的「三次握手就是从这里开始」的

  • write():客户端写入要发送的数据

  • read():客户端读取服务端返回的数据

  • close():断开连接,「四次挥手」,给客户端发送断开连接的信息

相关视频推荐

100行代码开启自己的协议栈,《tcp/ip详解》的代码注解

10道网络八股文,每道都很经典,让你在面试中逼格满满

学习地址:c/c++ linux服务器开发/后台架构师

需要C/C++ Linux服务器架构师学习资料加qun812855908(资料包括C/C++,Linux,golang技术,内核,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK,ffmpeg,大厂面试题 等)

基于 UDP

​这里我就不细写了,其实大同小异,从流程图上就可以看到

因为 UDP 是无状态的,所以对于服务端来说没有连接,并且其会在调用 Recvfrom() 方法后就收客户端的请求,并一直阻塞,直到收到信息

Socket TCP 是如何建立连接的

在 Socket 绑定完服务器的地址后,就开始和服务器建立连接了,TCP 建立连接的方式其实就是大名鼎鼎三次握手了

  • ​第一次握手:A 的 TCP 进程创建一个 传输控制块 TCB ,然后向 B 发出连接请求报文段。之后将同步位 SYN 设置为 1,同时选择一个初始序列号 seq=x,这时客户端 A 进入到 SYN-SENT(同步已发送)状态。

  • 第二次握手:B 收到连接请求报文段,如果同意建立连接,则向 A 发送确认。在确认报文段中 同步位 SYN=1、确认位 ACK=1、确认号 ack=x+1,同时也为自己选择一个初始序列号 seq=y,这时服务器 B 进入 SYN-RCVID 状态。

  • 第三次握手:A 收到 B 的确认以后,再向 B 发出确认。确认报文 ACK=1、确认号ack=y+1。这时A进入到 ESTAB-LISHED 状态。当B接收到A的确认后,也进入 ESTAB-LISHED 状态。连接建立完成

三次握手发生在 socket 的哪几个函数中

  • ​当客户端调用 connect 时,触发了连接请求,向服务器发送了SYN 信号,这时 connect 进入阻塞状态;

  • 服务器监听到连接请求,即收到 SYN,调用 accept 函数接收,进入阻塞状态,在此之前会尽力 socket、bind、listen 函数;然后返回相关的 syn 以及 ack 信号

  • 客户端接受到服务端的信息,此时 connect 完成,解除阻塞状态,并且向服务端发送 ack 信号

  • 服务端收到 ack, accept 阻塞解除,完成连接

在建立连接之后,connect() 就已经执行完毕了,服务端就可以向客户端发送数据了。

Socket TCP 是如何断开连接的

  • ​第一次挥手:A 先发送连接释放报文段,段首部的终止控制位 FIN=1,序号seq=u(等于A前面发送数据的最后一个序号加1);然后 A 进入 FIN-WAIT-1(终止等待1)状态,等待 B 的确认。

  • 第二次挥手:B 收到 A 的连接释放报文段后,立刻发出确认报文段,确认号 ack=u+1,序号 seq=v(等于 B 前面发送数据的最后一个序号加1);然后 B 进入 CLOSE-WAIT(关闭等待)状态。

  • 第三次挥手:A 收到 B 的确认报文段后进入到 FIN-WAIT-2(终止等待2)状态,继续等待 B 发出连接释放报文段;

  • 若 B 已经没有数据要发送,B 就会向 A 发送连接释放报文段,段首部的终止控制位 FIN=1,序号 seq=w(半关闭状态可能又发送了一些数据),确认号 ack=u+1,这时B进入 LAST-ACK(最后确认)状态,等待A的确认。

  • 第四次挥手:A收到B的连接释放报文段并发出确认,确认段中 确认位 ACK=1,确认号 ack=w+1,序号 seq=u+1;然后 A 进入到TIME-WAIT(时间等待)状态。当 B 再接收到该确认段后,B 就进入 CLOSED状态。

第四次挥手后为何要等待 2MSL

首先 2MSL 的时间是从客户端(A)接收到 FIN 后发送 ACK 开始计时的。如果在 TIME-WAIT 时间内,因为客户端(A)的 ACK 没有传输到服务端(B),客户端(A)又接收到了服务端(B)重发的 FIN 报文,那么 2MSL 时间会被重置。等待 2MSL 原因如下

  • 1.得原来连接的数据包消失

  • 如果B没有收到自己的ACK,会超时重传FiN那么A再次接到重传的FIN,会再次发送ACK

  • 如果B收到自己的ACK,也不会再发任何消息

在最后一次挥手后 A 并不知道 B 是否接到自己的信息, 包括 ACK 是以上哪两种情况,A 都需要等待,要取这「两种情况等待时间的最大值,以应对最坏的情况发生」,这个最坏情况是:去向ACK消息最大存活时间(MSL) + 来向FIN消息的最大存活时间(MSL)。这刚好是2MSL,这个时间,足以使得原来连接的数据包在网络中消失。

  • 2.保证 ACK 能被服务端接收到从而正确关闭链接

因为这个 ACK 是有可能丢失的,会导致服务器收不到对 FIN-ACK 确认报文。假设客户端不等待 2MSL ,而是在发送完 ACK 之后直接释放关闭,一但这个 ACK 丢失的话,服务器就无法正常的进入关闭连接状态。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值