专栏名称: 脚本之家
脚本之家(jb51.net)是国内专业的网站建设资源、脚本编程学习类网站,以后将为大家分享更多有用的信息,希望大家多多支持宣传。
目录
相关文章推荐
西藏文旅  ·  游客注意!西藏部分地方有中雪(雨) ·  20 小时前  
西藏文旅  ·  游客注意!西藏部分地方有中雪(雨) ·  20 小时前  
网信西藏  ·  拉萨还要下雪! ·  2 天前  
架构师之路  ·  巧用CAS,一分钟实现分布式ID生成器!(第 ... ·  3 天前  
西藏发布  ·  为期一个月!林芝桃花节开幕时间定了 ·  3 天前  
西藏发布  ·  为期一个月!林芝桃花节开幕时间定了 ·  3 天前  
51好读  ›  专栏  ›  脚本之家

背了一年的计网八股,还不知道什么是 Socket?

脚本之家  · 公众号  ·  · 2023-04-05 17:00

正文

脚本之家 设为“ 星标

第一时间收到文章更新

来源公众号:飞天小牛肉  ID:CS-Wiki

已获得原公众号的授权转

前言

不明白 Socket 是什么的主要原因其实就是没有实际的网络编程经验,就没有在代码里用过 Socket,背来背去还是脑袋一片浆糊,很正常,看完这篇文章肯定就清楚了(狗头)

TCP 四元组

要说 Socket,那当然不能绕过 TCP 了,各位不妨先来思考下如何确定一个 TCP 连接?

以小黑和小白为例,他们分别位于不同的小区,小黑找小白玩,需要知道小白的小区和门牌号,也就是说,小区 + 门牌号就是小白家的入口,知道了这个入口,小黑就能找到小白。反之也是同样的。

小区类比于 IP 地址,门牌号类比于端口号, IP 地址 + 端口号 (小区 + 门牌号) 就能唯一确定一个程序。光有小区不行,光有门牌号也不行,所以这就是为什么说网络层负责建立主机到主机的通信(IP 地址),传输层负责建立端口到端口的通信(端口号)了。

这个很好记忆,你上线一个网站的时候,如果没有绑定域名的话,那么就只能通过 IP 地址 + 端口号(默认是 80,浏览器上不显示)访问。

总结下就是, TCP 四元组 可以唯一的确定一个连接,四元组包括如下:

  • 目的 IP 地址
  • 目的端口
  • 源 IP 地址
  • 源端口

其中:

  • IP 地址(源地址和目的地址,32位)是在 IP 头部中
  • 端口号(源端口和目的端口,16位)是在 TCP 头部中

Socket

掌握了四元组这个基本概念,我们再来解释 Socket。

上文说过,小区 + 门牌号是住宅的入口, IP 地址 + 端口号是一个程序的入口,这个入口就是 Socket ,那么服务端和客户端之间想要进行通信,只要互相暴露出自己的入口(Socket),就能够找到彼此了。

更严谨来说, Socket 封装了基本的通信功能,是 TCP/IP 协议的基本操作单元

以 Java 中的 Socket 类为例,服务端和客户端首先都需要调用构造函数创建 Socket 暴露自己的入口(绑定 IP 地址和端口,也可以调用 bind 方法进行绑定)

光暴露了入口还不行,你还得竖起耳朵听,不然别人来敲门你听不见那也没法通信啊,所以接下来服务端调用 accept() 方法,该方法将一直等待,直到客户端请求服务端的入口,再就是 TCP 三次握手建立连接的过程了。

服务端 Socket 创建一般使用 ServerSocket 类,该类提供了非常重要的 accept(建立连接) :

那客户端是如何请求服务端的入口的呢?也就是是如何发起连接的呢,客户端在创建好 Socket 后,调用 connect(host, port) 函数发起连接,该函数需要指明服务端的 IP 地址和端口号。

所以说, TCP 三次握手其实是发生在客户端 connect 和服务端 accept 两个函数之间 。握手完了就可以通过 read() write() 来通信啦。这里需要重点注意的是: 监听的 Socket 和真正用来传数据的 Socket 是两个不同的 Socket

  • 一个是 监听 Socket
  • 一个是 已连接 Socket

看下上述的 ServerSocket.accept 方法就明白了, accept 会返回一个 Socket 对象,后续服务端和客户端之间的数据传输都用这个 Socket:

事实上,在三次握手的过程中,内核(Kernel)为每个连接都维护了两个队列:

  • TCP 半连接队列 :这个队列存储没有完成三次握手的 Socket,此时服务端处于 syn_rcvd 的状态;
  • TCP 全连接队列 :这个队列存储已经完成了三次握手的 Socket,此时服务端处于 established 状态;

当 TCP 全连接队列不为空后,服务端的 accept() 函数,就会 从内核中的 TCP 全连接队列里拿出一个已经完成连接的 Socket 并返回,用于后续服务端和客户端的通信。

总结

综上, 基于 TCP 协议的 Socket 调用过程就结束了,下面由贴心助理 ChatGPT 总结下:

以下全是 ChatGPT 生成的结果 ,没有一个字是我写的(😂),虽然是我引导了很多轮的结果,但是输入合适的 Promt 并配合上下文 ChatGPT 基本能输出 90% 想要的内容,确实太强了

文字解释

代码示例







请到「今天看啥」查看全文