郑州网站制作需要多少钱,wix网站怎么做,网站建设售后服务费包括哪些,运维需要掌握哪些知识我相信大家在面试过程中或多或少都会被问到这样一个问题#xff1a;你能解释一下什么是 socket 吗 我记得我当初的回答很是浅显#xff1a;socket 也叫套接字#xff0c;用来负责不同主机程序之间的网络通信连接#xff0c;socket 的表现方式由四元组#xff08;ip地址你能解释一下什么是 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 的组合你可以在茫茫互联网中找到属于你的梦中情机并且与之通信 所以你在设计网络传输功能初期定义了一个数据结构 socksock 里面包含了 ip 和 port 字段假设用 C 语言实现 在 Linux 中以 CentOS 7举例在头文件/usr/include/netinet/in.h可以看到负责套接字地址的 sock 结构体 sin_family 字段为 AF_INETsin_port 表示端口号sin_addr 表示 IPv4 地址是一个 struct in_addr类型的结构体 sin6_family 字段为 AF_INET6sin6_port 表示端口号sin6_addr 表示 IPv6 地址是一个 struct in6_addr 类型的结构体 解决了定位问题之后我们知道在计算机网络中有很多协议这些协议规定了计算机之间的通信方式 比如你是选用可靠的 TCP 协议去进行网络通信还是相对不可靠的 UDP 协议 不同的网络协议还对应着不同的网络通信场景如果你选择了 TCP协议你还得考虑例如滑动窗口、超时重传这些场景 所以有了 ip 和 port 还不行你还需要定义新的数据结构用来维护网络协议以及对应的网络场景 又因为不同的网络协议中有一些功能相似的方法例如收发数据于是你决定将不同协议中公共的部分提取出来通过”继承“的方式来实现功能复用 所以可以先定义一个名为 sock 的数据结构然后定义”继承“ sock 的各类 sock PSLinux 内核是用 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 查看