socket 到底是个啥
我相信大家在面试过程中或多或少都会被问到这样一个问题:你能解释一下什么是 socket 吗
我记得我当初的回答很是浅显:socket 也叫套接字,用来负责不同主机程序之间的网络通信连接,socket 的表现方式由四元组(ip地址:端口)组成
那么今天,咸鱼将跟大家打开 socket 的神秘大门,不但要搞清楚 socket 的概念,最好还能够了解它的底层实现
我们首先查看一下 socket 的翻译
我们看到,socket 可以翻译成插座、插头
那现在请想象这么一个场景:给手机充电时,你将充电插头插入电源插座里面,是不是意味着插座与充电插头连接起来了
在计算机世界中,socket 翻译成套接字,通过 socket 我们可以与某台服务器进行连接,而建立连接的过程,你可以脑补成将充电插头插进插座的过程
socket 使用场景
假设我们想要将数据从 A 电脑的某个进程传送到 B 电脑的某个进程(比如咸鱼用微信发信息给冰冰)
那么在与对方聊天的过程中,其实就是这两台电脑中的微信进程相互传输数据的过程
在这个过程中,两台电脑各自调用 socket 方法,然后会得到一个 fd 句柄(socket_fd),这个 fd 句柄就相当于 socket 的身份证号
得到 fd 句柄之后:
-
服务端执行 bind()、listen()、accept() 方法等待客户端建立连接的请求
-
客户端执行 connect() 方法向服务端发起连接
-
连接建立起来之后,两端都可以执行 send()、recv() 方法来互相传递数据
PS:对于不同的传输层协议,上面这个过程是不一样的,详情可以查看我之前的文章《Python 网络编程》
TCP 协议
UDP 协议
socket 底层设计
我们知道了 socket 是用来实现网络传输功能的,它负责不同主机进程之间的网络通信连接
我将上面的问题改一下,把 ”socket 是什么“ 改成 ”如果让你来实现一个网络传输功能,你会怎么设计“
网络传输功能,简单点来讲就是两端服务器之间进行网络通信并互相收发数据,收发数据也就是读写数据
首先我们会遇到第一个问题:茫茫互联网中你怎么能找到那台梦中情机
聪明的你肯定会想到——ip地址!我们用 ip 地址来定位电脑
找到了你的梦中情机之后,你会发现,一台电脑上面这么多进程,我怎么才能找到与我通信的那个进程(比如说微信)
聪明的你很快就想到了用端口号(port)
可以这么理解,ip 地址是用来定位街区的,而端口号 port 对应这个街区中的门牌号,通过 ip +port 的组合,你可以在茫茫互联网中找到属于你的梦中情机并且与之通信
所以你在设计网络传输功能初期,定义了一个数据结构 sock,sock 里面包含了 ip 和 port 字段(假设用 C 语言实现)
在 Linux 中(以 CentOS 7举例),在头文件/usr/include/netinet/in.h
可以看到负责套接字地址的 sock 结构体
sin_family 字段为 AF_INET,sin_port 表示端口号,sin_addr 表示 IPv4 地址,是一个
struct in_addr
类型的结构体sin6_family 字段为 AF_INET6,sin6_port 表示端口号,sin6_addr 表示 IPv6 地址,是一个 struct in6_addr 类型的结构体
解决了定位问题之后,我们知道在计算机网络中有很多协议,这些协议规定了计算机之间的通信方式
比如你是选用可靠的 TCP 协议去进行网络通信,还是相对不可靠的 UDP 协议
不同的网络协议还对应着不同的网络通信场景,如果你选择了 TCP协议,你还得考虑例如滑动窗口、超时重传这些场景
所以有了 ip 和 port 还不行,你还需要定义新的数据结构用来维护网络协议以及对应的网络场景
又因为不同的网络协议中有一些功能相似的方法(例如收发数据),于是你决定将不同协议中公共的部分提取出来,通过”继承“的方式来实现功能复用
所以可以先定义一个名为 sock 的数据结构,然后定义”继承“ sock 的各类 sock
PS:Linux 内核是用 C 语言实现的,在 C 语言中没有继承这个概念,你可以简单将这个继承理解成 xx_sock 基于 sock 进行了扩展,xx_sock 是 sock 的进阶版
-
sock
:最基础的结构,用来维护任何网络协议都会用到的收发数据缓冲区(公用部分) -
inet_sock
:负责网络传输功能的 sock,在 sock 基础上加了 TTL(网络生存时间)、ip 和 port 这些跟网络传输相关的字段信息 -
inet_connection_sock
:面向连接的 sock,在inet_sock
基础上添加了面向连接的协议里相关字段,比如 accept 队列,数据包分片大小,握手失败,重试次数等;虽然我们现在提到面向连接的协议就是指 TCP,但从设计上 Linux 需要支持扩展其他面向连接的新协议,比如 SCTP 协议,所以说tcp_sock
则是在这个基础上实现的真正的 TCP 协议专用 sock 结构
上面例子中的这些 sock 都可以在系统上直接找到,以 CentOS 7 为例
现在你用代码实现了这一堆数据结构——sock,不同的 sock 分别实现自己职责内的功能(负责面向连接的数据结构 inet_connection_sock
、负责 UDP 协议的数据结构 udp_sock
等等)
但是你需要这些 sock 去跟硬件网卡交互才能实现网络传输的功能,既然需要跟硬件交互,那就说明需要比较高的操作系统权限
同时考虑到性能和安全,这套数据结构不能放在用户态,需要给它放到系统内核里面
既然这套数据结构在内核里,处在用户态的程序想要用这套数据结构来实现网络传输功能该怎么办呢?
除此之外,处在用户态的程序并不关心也不知道你这套数据结构在底层内核是怎么操作的,功能是怎么实现的,它只关心结果
于是你想到了用接口调用的方式——你将一个个功能抽象一个个接口,以后别人只需要调用这些接口,就可以让内核中这一大堆复杂的数据结构去实现指定功能
又因为在 Linux 中一切皆文件,你索性将这些 sock 封装成文件,当用户态的程序去调用你提供的接口时,需要先创建一个 sock 文件
这个新生成的 sock 文件有一个文件句柄 fd,用户态的程序只需要拿着这个 fd 就可以对内核中的 sock 进行操作
上面有说到,你将不同的数据结构(inet_sock
、tcp_sock
等等)抽象成一个个 API 接口,以后别人只需要调用这些 API 接口就可以驱动我们写好的这一大堆复杂的数据结构去进行网络传输
下面列出了一些常见的接口:
-
send
-
recv
-
bind
-
listen
-
connect
到这里,整个网络传输功能就已经基本实现了。上面列举出来的这些方法,其实就是 socket 提供出来的接口
到这里,我们对 socket 有了一个更深地了解——socket 其实相当于一个接口层,它处在内核态和用户态之间:
-
向上用户态
-
为处在用户态的程序提供 API 接口,方便用户态程序实现网络传输功能
-
-
向下内核态
-
对网卡进行操作,负责网络传输工作
-
或者你也可以这么理解,处在用户态的程序通过 socket 提供的接口,将网络传输的这部分工作外包给了 Linux 内核
我们以 tcp 协议为例子来看下 python 中是如何操作 socket 的
在客户端中,程序首先调用 socket 提供的 socket 方法创建一个 socket 文件来获得 socket 句柄,然后调用 connect 方法,这时候内核会根据 socket_fd 找到对应的 sock 文件
再根据文件里的信息找到处在内核的 sock 结构,通过 sock 结构与服务端进行三次握手建立连接
连接建立好之后,客户端调用 send 方法来进行数据传输,sock 中定义了一个发送缓冲区和接收缓冲区,其实就是一个链表,链表上面放着一个个等待发送或接收的数据
总结
我们再次回到那个问题——socket 是什么?
sock(或 socket)是操作系统内核提供的一种数据结构,用于实现网络传输功能
基于不同的网络协议以及应用场景,衍生了各种类型的 sock
每个网络层协议都有相应的 sock 结构体来管理该层协议的连接状态和数据传输。各类 sock 操作硬件网卡,就实现了网络传输的功能
为了将这些功能让处在用户态的应用程序使用,不但引入了 socket 层,还将各类功能的实现方式抽象成了 API 接口,供应用程序调用
同时将 sock 封装成文件,应用程序就可以在用户层通过文件句柄(socket fd)来操作内核中 sock 的网络传输功能
这个 socket fd 是一个 int 类型的数字,而 socket 中文翻译叫做套接字,结合这个 socket fd,你是不是可以将其理解成:一套用于连接的数字
而 socket 分 Internet socket 和 UNIX Domain socket,两者都可以用于不同主机进程间的通信和本机进程间的通信
只是前者采用的是基于 IP 协议的网络通信方式,而后者采用的是基于本地文件系统的通信方式
关于 UNIX Domain socket,可以通过 netstat -x
查看
相关文章:

socket 到底是个啥
我相信大家在面试过程中或多或少都会被问到这样一个问题:你能解释一下什么是 socket 吗 我记得我当初的回答很是浅显:socket 也叫套接字,用来负责不同主机程序之间的网络通信连接,socket 的表现方式由四元组(ip地址&am…...

奥威BI—数字化转型首选,以数据驱动企业发展
奥威BI系统BI方案可以迅速构建企业级大数据分析平台,可以将大量数据转化为直观、易于理解的图表和图形,推动和促进数字化转型的进程,帮助企业更好地了解自身的运营状况,及时发现问题并采取相应的措施,提高运营效率和质…...
vue中swiper使用
1.引包 说明:导入相应js引css import "Swiper" from "swiper" import "swiper/css/swiper.css"; import "swiper/js/swiper"; 2.结构 说明:必要的结构使用;直接封装成一个组件 <template>…...
webpack与vite区别
webpack和Vite作为两种常用的前端构建工具,主要有以下几点区别: 构建速度 webpack采用“打包”的方式构建,需要将所有模块打包成几个大的bundle文件,构建速度较慢。 Vite采用了“按需编译”的方式,只在浏览器请求时才编译对应模块,启动速度更快。 dev server webpack dev s…...

GLSL用于图像处理
Pipeline 硬件处理顶点和片段的Pipeline 软件的输入 顶点着色器 顶点的glsl 输入–特殊全局变量 变量 类型 指定函数 描述 gl_ Vertex vec4 glVertex 顶点的全局空间坐标 gl_Color vec4 glColor 主颜色值 gl_SecondaryColor vec4 glSecondaryColor 辅助颜色值 gl_Normal …...

即将发布的 Kibana 版本可运行 Node.js 18
作者:Thomas Watson Kibana 构建在 Node.js 框架之上。 为了确保每个 Kibana 版本的稳定性和使用寿命,我们始终将捆绑的 Node.js 二进制文件保持为最新的最新长期支持 (LTS) 版本。 当 Node.js 版本 18 升级到 LTS 时,我们开始将 Kibana 升级…...
基于遗传算法改进的支持向量机多分类仿真,基于GA-SVM的多分类预测,支持相机的详细原理
目录 背影 支持向量机SVM的详细原理 SVM的定义 SVM理论 遗传算法的原理及步骤 SVM应用实例,基于遗传算法优化SVM的多分类预测 完整代码包括SVM工具箱:https://download.csdn.net/download/abc991835105/88175549 代码 结果分析 展望 背影 多分类预测对现代智能化社会拥有重…...

MySQL5.7源码编译Debug版本
编译环境Ubuntu22.04LTS 1 官方下载MySQL源码 https://dev.mysql.com/downloads/mysql/?spma2c6h.12873639.article-detail.4.68e61a14ghILh5 2 安装基础软件 cmakeclangpkg-configperl 参考:https://dev.mysql.com/doc/refman/5.7/en/source-installation-prere…...

ORA-48913: Writing into trace file failed, file size limit [50000000] reached
检查某环境的alert_orcl1.log时,发现有很多的ORA-48913报错,细节如下 Sat Jul 22 19:34:04 2023 Non critical error ORA-48913 caught while writing to trace file "/u01/app/oracle/diag/rdbms/orcl/orcl1/trace/orcl1_dw00_138010.trc" E…...
线上Zookeeper问题解决记录
zookeeper问题: 日志目录: /home/cmccdata/app/zookeeper/logs dataDir/home/cmccdata/app/zookeeper/data/zoodata dataLogDir/home/cmccdata/app/zookeeper/data/zoolog 问题0: 2023-08-03 17:15:43,139 [myid:1] - WARN [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:…...

Docker极速安装Jenkins
安装 Jenkins 是一个常见的任务,使用 Docker 进行安装可以简化该过程并确保环境一致性。以下是在 Docker 中安装 Jenkins 的详细步骤: 安装 Docker: 首先,请确保您已在目标机器上安装了 Docker。根据您的操作系统,可以在 Docker 官…...
TransnormerLLM 中 FlashLinearAttention 的纯pytorch实现
Github 仓库:https://github.com/One-sixth/flash-linear-attention-pytorch flash-linear-attention-pytorch 纯 Pytorch 实现 TransnormerLLM 中快速线性注意力算子。 用于学习目的。 如果你希望用于训练模型,你可能要修改为 CUDA 或 Triton 的实现&…...

从NPM注册中心获取包
目录 1、搜索和选择要下载的包 1.1 为什么使用 1.2 工作原理 1、质量 2、维护 3、受欢迎程度 4、名气 1.1、开始搜索包 2、在本地安装下载和安装软件包 2.1 安装未限定作用域的包 2.2 安装有作用域的公共包 2.3 安装私有包 2.4 测试包安装 2.5 已安装的软件包版本…...

Elastic的下载
文章目录 ElasticSearch的下载扩展1(ElasticSearch 与 JDK 版本 适配)扩展2(访问 http://192.168.1.200:9200 没有显示信息)扩展3(免密登录) ElasticSearch的下载 官方下载网址:https://www.el…...

day52-Redis
Redis 1.Redis 1.1 RESP连接Redis 1.2 定义:是一个高性能的key-value数据库(非关系型数据库) 1.3 数据类型: key键的类型是字符串类型; 值的类型有五种:字符串String,哈希hash࿰…...

高效处理矢量大数据的高可用解决方案
高效处理矢量大数据的高可用解决方案 解决方案目标 存储海量矢量数据实时分析海量矢量数据实现海量矢量数据的可视化提供高可用、高性能和高可拓展性解决方案概述 海量数据查询与可视化 系统技术流程 方案一 数据存储: PostgreSQL+PostGIS(矢量数据存储和空间分析)数据服务…...

Docker Compose构建lnmp
目录 Compose的优点 编排和部署 Compose原理 Compose应用案例 安装docker-ce 阿里云镜像加速器 安装docker-compose docker-compose用法 Yaml简介 验证LNMP环境 Compose的优点 先来了解一下我们平时是怎么样使用docker的?把它进行拆分一下: 1…...
Flutter开发问题记录
1. Q:Mac电脑通过AndroidStudio运行软件到iphone报错 automatically assigning platform iOS with version 10.0 on target Runner because no platform was specified. A:项目中ios目录下,Podfile文件第2行 platform :ios, ‘11.0’,取消注释 2. Q:Mac电脑通过And…...

如何使用本地mock数据
当后端同事接口数据还未完成,我们前端开发需要使用数据时,怎么办呢?这里可以自己本地mock数据先用着啦!仅在开发时使用 1. 创建一个 xxx.js文件,对外暴露一个数组; 对新建js文件编写导出,返回数…...

XXL-JOB定时任务框架(Oracle定制版)
特点 xxl-job是一个轻量级、易扩展的分布式任务调度平台,能够快速开发和简单学习。开放源代码并被多家公司线上产品使用,开箱即用。尽管其确实非常好用,但我在工作中使用的是Oracle数据库,因为xxl-job是针对MySQL设计的ÿ…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...

label-studio的使用教程(导入本地路径)
文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
JVM垃圾回收机制全解析
Java虚拟机(JVM)中的垃圾收集器(Garbage Collector,简称GC)是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象,从而释放内存空间,避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...
OkHttp 中实现断点续传 demo
在 OkHttp 中实现断点续传主要通过以下步骤完成,核心是利用 HTTP 协议的 Range 请求头指定下载范围: 实现原理 Range 请求头:向服务器请求文件的特定字节范围(如 Range: bytes1024-) 本地文件记录:保存已…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...

Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...

tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...