当前位置: 首页 > news >正文

龙岗公司网站数字创意设计包括哪些方面

龙岗公司网站,数字创意设计包括哪些方面,三合一模板网站,网站开发教程公司#x1f52d; 嗨#xff0c;您好 #x1f44b; 我是 vnjohn#xff0c;在互联网企业担任 Java 开发#xff0c;CSDN 优质创作者 #x1f4d6; 推荐专栏#xff1a;Spring、MySQL、Nacos、Java#xff0c;后续其他专栏会持续优化更新迭代 #x1f332;文章所在专栏 嗨您好 我是 vnjohn在互联网企业担任 Java 开发CSDN 优质创作者 推荐专栏Spring、MySQL、Nacos、Java后续其他专栏会持续优化更新迭代 文章所在专栏网络 I/O 我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识 向我询问任何您想要的东西IDvnjohn 觉得博主文章写的还 OK能够帮助到您的感谢三连支持博客 代词: vnjohn ⚡ 有趣的事实音乐、跑步、电影、游戏 目录 前言I/O 复用模型图解分析SELECT 函数POLL 函数两者函数区别 源码实践服务端代码流程说明测试挥手问题 NIO、I/O 多路复用总结 前言 Unix/Linux 下可用的 I/O 模型有以下五种 阻塞式 I/O非阻塞式 I/OI/O 复用(select、poll)信号驱动式 I/O(SIGIO)异步 I/O 在 Linux 中操作内核时所有的无非三种操作分别是输入、输出、报错输出 0-输入 1-输出 2-报错输出 一个输入操作通常包括两个不同的阶段 等待数据准备好从内核向进程复制数据 对于一个套接字Socket的输入操作第一步通常涉及等待数据从网络中当所等待分组到达时它被复制到内核中的某个缓冲区第二步就是把数据从内核缓冲区复制到应用进程缓冲区 I/O 复用模型 I/O 复用I/O multiplexingSELECT、POLL阻塞在这两个系统「用户态、内核态」调用中的某一个之上而不是阻塞在真正的 I/O 系统调用上 将阻塞于 select 调用等待数据报套接字变为可读当 select 返回的套接字可读这一条件时再调用 recvfrom 把所读的数据报复制到应用进程缓冲区 使用 select 的优势在于我们可以等待多个描述符就绪 与 I/O 复用密切相关的另外一种模型就是在多线程的场景下使用阻塞时 I/O 模型 BIO两者极其相似但它没有使用 select 阻塞在多个文件描述符上而是使用多个线程「每个文件描述符分配一个线程的方式」这样每个线程都可以自由地调用诸如recvfrom 之类的阻塞式 I/O 系统调用了. 图解分析 SELECT 属于 synchronous I/O multiplexing 同步 I/O 多路复用 它允许程序监视多个文件描述符等待一个或多个文件描述符尾某种类型read、write的 I/O 操作 SELECT 仅用一次系统调用recv recvfrom 接收数据都只是会接收具体可操作的文件描述符数量例如图中带有 data 的 IO 操作 SELECT 函数 该函数允许进程指示内核等待多个事件「文件描述符」中的任何一个发生并且只有在一个或多个时间发生或经历一段指定的时间后才能唤醒它 以上图中的 IO 块作为例子延迟当调用 select 函数时告知内核仅在以下情况发生时才进行返回 IO 集合1、7 中任何描述符准备好读IO 集合4、5 中任何描述符准备好写IO 集合2、3、6 中任何描述符有异常条件待处理这个过程经历了 Xxx 秒 当调用 select 时要告知内核对哪些描述符read、write、exception感兴趣以及需等待多长时间 通过 Linux 内核帮助文档来学习 SELECT man 2 select 在已经有的 Linux 内核中已经不支持使用 SELECT 函数了查看文档时会出现none - deprecated system calls例如内核版本Linux version 5.11.12-300.el7.aarch64 当然在 x86_64 内核版本仍然可以查看该帮助文档例如内核版本Linux version 3.10.0-1160.90.1.el7.x86_64 可通过 cat /proc/version 命令来查看 在它的文档中可以看到以下这些函数都是同步 I/O 多路复用使用的. select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplexing 观察 select 函数源码如下 int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);nfds代表文件描述符的数量 *readfds代表读取的文件描述符 *writefds代表写入的文件描述符 *exceptfds代表异常条件的文件描述符 *timeout代表等待多长的时间 它的 timeval 结构用于指定这段时间的秒数、微妙数结构源码如下 struct timeval {long tv_sec; /* seconds */long tv_usec; /* microseconds */ };其中 select timeout 参数有以下三种可能性 永远等待下去仅在有一个描述符准备好 I/O 时才返回为此可以将该参数设置为空等待一段固定的时间在有一个描述符准备好 I/O 时才返回但是不会超过该参数所设置的秒数、微妙数根本不等待检查描述符完成后立即返回称之为 轮询(polling)为此该参数中的秒数、微妙数必须设置为 0 前面两种可能性的等待通常会被进程在等待期间捕获的信号中断并从信号处理函数中返回 其中 select readfds、writefds、exceptfds 三个参数指向的是一组描述符结果集 最大描述符数 SELECT 最大描述符数大多数应用程序不会用到许多描述符臂如说很少能够找到一个同时使用几百个描述符的应用程序然而使用那么多描述符的应用程序确实村再它们往往使用 select 来复选描述符。最初设计 select 时操作系统通常对每个进程可用的最大描述符数设置了上限 取自于 4.4 BSD sys/types.h 头文件中最大的描述符在内核被定义为一个常量FD_SETSIZE 值为 1024此时可以使用 poll 代表 select这样可以避免描述符有限的问题. POLL 函数 执行与 SELECT 类似的任务它等待一组文件描述符中的一个准备好执行 I/O不过在处理流设备时它能够提供额外的信息 int poll(struct pollfd *fds, nfds_t nfds, int timeout);第一个参数是一个指向一个结构数组第一个元素的指针每个数组元素都是一个 pollfd 结构用于指定测试某个给定描述符 fd 的条件. struct pollfd {int fd; /* file descriptor */short events; /* requested events */short revents; /* returned events */ };要测试的条件由 events 成员指定函数在相应的 revents 成员中返回该描述符的状态每个描述符都有两个变量一个为调用值另外一个为返回结果从而避免了「值-结果」参数这两个成员的每一个都由指定某个特定条件的一位或多位构成 值-结果参数代表传入的值和输出的值不是同一个参数对比 select 来说它的中间三个参数都是「值-结果」参数 字段 events代表一个输入参数一个指定应用程序对文件描述符 fd 感兴趣的事件的位 bit 掩码若将此字段指定为零则忽略 fd 中所有的事件并且 revents 返回 0 字段 revents代表一个输出参数由内核填充实际发生的事件事件返回的 bit 位可以包括事件中指定的任何位也可以包括POLLERR、POLLHUP 或 POLLNVAL 值之一 POLLERR、POLLHUP 或 POLLNVAL 这三个值在 events 字段中设置是没有意义的当相应的条件为真时将在 revents 字段中设置. 用于指定 events 标志以及 revents 标志的一些常量值如下表格 常量值作为 events 输入作为 events 结果说明POLLIN☑️☑️普通或优先级带数据可读POLLRDNORM(Read Normal)☑️☑️普通数据可读POLLRDBAND(Read Band)☑️☑️优先级带数据可读POLLPRI(Priority)☑️☑️高优先级数据可读POLLOUT☑️☑️普通数据可写POLLWRNORM(Write Normal)☑️☑️普通数据可写POLLWRBAND(Write Band)☑️☑️优先级带数据可写POLLERR(Error)☑️发生错误条件(仅输出)POLLHUP(Hang up)☑️发生挂起(仅输出)POLLNVAL☑️无效请求fd未打开(仅输出)描述符不是一个打开的文件 该表格分为三个部分第一部分是处理输入的四个常量值第二部分是处理输出的三个常量值第三部分是处理错误的三个常量值其中第三部分的常量值不能在 events 中设置但是当相应条件第三部分常量值存在时就在 revents 中返回. POLL 识别三类数据普通(Normal)、优先级带(Priority Band)、高优先级(Hign Priority) POLLIN 可被定义为 POLLRDNORM、POLLRDBAND 的逻辑或 第二个参数 nfds调用者应该在 nfds 中指定 fds 数组中的项数 第三个参数 timeouttimeout 参数指定 poll() 将阻塞的最小毫秒数这个时间间隔将四舍五入到系统时钟粒度内核调度延迟意味着阻塞时间间隔可能会超出一小部分在 timeout 中指定负值意味着无限超时。指定超时为零将导致 poll() 立即返回即使没有文件描述符准备好 负值无限超时 0立即返回 正数阻塞的最小毫秒数 两者函数区别 在 SELECT 函数中提及到了 FD_SETSIZE每个描述符集最大的描述符数量当有了 POLL 就无须考虑这个问题因为分配了一个 pollfd 结构的数组并把数组中元素的数目通知内核成了调用者的责任内核不再需要知道 fd_setSELECT 中的参数类型 固定大小的数据类型 POSIX 规范对 select、poll 都有需要然而从当今的可移植性来考虑支持 select 系统比支持 poll 系统要多另外除了 select 函数还定义了 pselect 函数它能够处理信号阻塞并提供了更高时间分辨率的 select 的增强版本而在 POSIX 规范中没有为 poll 定义类似的东西. 源码实践 以下代码是服务端侧的所有代码处理三种类型事件注册事件、写事件、读事件客户端代码可以沿用之前 BIO、NIO 中的源码或者说可以在命令窗口通过 nc 命令进行连接 服务端代码 package org.vnjohn.select;import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Iterator; import java.util.Set;/*** author vnjohn* since 2023/12/7*/ public class SelectMultiplexingSocketThread extends Thread {private Selector selector null;/*** 初始化 socket 服务端实例进行 accept*/public void initServer() {try {ServerSocketChannel server ServerSocketChannel.open();server.configureBlocking(false);server.bind(new InetSocketAddress(8090));// select、poll、*epoll 都是使用同样的方式打开selector Selector.open();server.register(selector, SelectionKey.OP_ACCEPT);} catch (IOException e) {e.printStackTrace();}}Overridepublic void start() {initServer();System.out.println(Socket Server start...);try {while (true) {// select()// select(long timeout)毫秒级别的等待while (selector.select() 0) {SetSelectionKey selectionKeys selector.selectedKeys();IteratorSelectionKey iterator selectionKeys.iterator();while (iterator.hasNext()) {SelectionKey key iterator.next();iterator.remove();if (key.isAcceptable()) {acceptHandler(key);} else if (key.isReadable()) {// 只处理了{read}并注册一个对这个 key 感兴趣的 write 事件readHandler(key);} else if (key.isWritable()) {// 写事件-当 Send-Queue 为空时就一定会给你返回可以写的事件就会回调我们的写方法// 多路复用器能不能写是参考Send-Queue 有没有空间// 1、你准备好要写什么了这是第一步// 2、第二步你才关心 Send-Queue 是否有空间// 3、so读 read 一开始就要注册但是 write 依赖以上关系什么时候用什么时候注册// 4、若一开始就注册了 write 事件进入死循环一直调起writeHandler(key);}}}}} catch (IOException e) {e.printStackTrace();}}/*** 该方法用于接收新的客户端连接进来在此处就会向 SELECT 结果集注册一个 read 事件用于接收客户端发送过来的数据** param key*/public void acceptHandler(SelectionKey key) {try {ServerSocketChannel ssc (ServerSocketChannel) key.channel();SocketChannel client ssc.accept();// NIO-NON_BLOCKINGclient.configureBlocking(false);// 分配给 8M 写入的空间ByteBuffer buffer ByteBuffer.allocate(8192);client.register(selector, SelectionKey.OP_READ, buffer);System.out.println(-------------------------------------------);System.out.println(new SocketClient client.getRemoteAddress());System.out.println(-------------------------------------------);} catch (IOException e) {e.printStackTrace();}}/**** param key*/private void writeHandler(SelectionKey key) {System.out.println(write handler...);SocketChannel client (SocketChannel) key.channel();ByteBuffer buffer (ByteBuffer) key.attachment();buffer.flip();// 判断服务端与客户端之间所在的缓冲区是否有数据存在有则进行写入操作将数据发送给客户端while (buffer.hasRemaining()) {try {client.write(buffer);} catch (IOException e) {e.printStackTrace();}}// 模拟一下业务延迟将注册进当前客户端的写事件注销掉下一次 select 时该事件不会被获取到// 当下一次客户端有数据要读取时写入该客户端的事件将会再次被注册try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}buffer.clear();key.cancel();try {client.close();} catch (IOException e) {e.printStackTrace();}}/*** 写事件针对当前选中的键做读取操作当读取到的数据不为空时在我们这里模拟写的操作此时 Send-Queue 肯定是有数据存在的* 所以在这里会模拟注册上一个 write 写事件把数据写给对应的客户端** param key 当前选中的键 文件描述符*/public void readHandler(SelectionKey key) {System.out.println(readHandler...);SocketChannel client (SocketChannel) key.channel();ByteBuffer buffer (ByteBuffer) key.attachment();buffer.clear();int read;try {while (true) {read client.read(buffer);if (read 0) {// 关心 OP_WRITE 其实就是关心 Send-Queue 是不是有空间client.register(key.selector(), SelectionKey.OP_WRITE, buffer);} else if (read 0) {break;} else {client.close();break;}}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {SelectMultiplexingSocketThread service new SelectMultiplexingSocketThread();service.start();} }通过模拟一个线程死循环的方式从 Selector 中获取所有的事件 Key通过 Key 类型的不同来执行不同的处理逻辑 注册 acceptacceptHandler 写 writewriteHandler 读 readreadHandler Selector 是 SELECT/POLL、Epoll 在 Java 应用程序中的抽象通过 Selector 优先选择的是 Epoll但是可以通过 -D 参数来修正主要就是更改所依赖的 Selector 实现类 select/poll-Djava.nio.channels.spi.SelectorProvidersun.nio.ch.PollSelectorProviderepoll-Djava.nio.channels.spi.SelectorProvidersun.nio.ch.EPollSelectorProvider Selector#open在 select/poll 模型下它和内核之间是没有交互的至于 Epoll 我们在下篇文章详细讲解SelectableChannel#register(Selector, SelectionKey.OP_ACCEPT)相当于在内核中是一个 listen 函数的调用 register在 select/poll 模型中JVM 里面会为其开辟一个数组将监听的文件描述符放进去期间是无系统调用的 Selector#select相当于就是内核中的 select(fd)、poll(fd) 函数 select 有两种方式支持调用select()、select(long timeout) 当设置了时间等待对应参数值的毫秒级别数返回 当未设置时间值为 0 也就是在介绍两个函数时所描述的一样0 代表立即返回设置了时间那么就等待一定时间以后才返回调用的结果 Selector#selectedKeys返回的是哪些有状态的 fds 文件描述符集合 SelectionKey 无论是什么样的多路复用器select、poll、epoll、kqueue只需要返回给我有状态的 fd 文件描述符即可 在 NIO 处理时是服务端这一侧对着每一个 fd 触发系统调用这样肯定是会浪费很多资源的而这里调用一次 select 就可以知道那么 fd 可以进行 R/W 在这个处理期间仍然会有两种类型的 Socket服务端 Socket 用于 accept 接收客户端连接的、客户端连接后的 Socket用于读写数据使用的 SelectionKey#isAcceptable准备好去接收新的 Socket 连接 在语义上accept 接收连接且返回新连接的 FD那么在 select/poll 中 FD 是如何存储的呢 因为在它们内核是没有空间的所在会在 JVM 中保存这些 FD 信息与第二点所描述的 SelectableChannel#register(Selector, SelectionKey.OP_ACCEPT) 存放在一起 在源码中的 acceptHandler 方法中出现 client.register(selector, SelectionKey.OP_READ, buffer) 将其装入 JVM 数组 SelectionKey#isReadable准备去接收读取的 Socket 连接在这里会将 R/W 同时都处理 在当前线程这个方法可能会被阻塞住处理过多的数据与逻辑 所以后面提出了 IO Threads 概念拿到数据以后就不管后续的事情了丢给后面的 worker 线程去进行处理 Redis 就是运用 epoll 模型同时它里面也有 IO Threads 概念Redis 工作线程虽然是单线程的但是它的网络 I/O、数据处理流都是采用多线程的 在源码中的 readHandler 方法中拿到 FD buffer 中的数据以后进行 read 读取有以下几种情况 1、若返回 0就会注册上一个 write 写事件把数据写给对应的客户端 2、若返回为 0就退出当前循环 3、若返回为 -1说明客户端已经断开连接同时将当前读取的 socket 连接关闭 流程说明 以上对源码以及相关的方法进行了说明接下来我们来测试 select/poll 模型与 TCP/IP 挥手的问题 通过 select/poll I/O 多路复用运行并 strace 追踪如上代码 1、先将首行 package 通过 vi 命令移除 2、编译源文件为 class 文件javac SelectMultiplexingSocketThread.java 3、以 select/poll 模型追踪运行 class 文件strace -ff -o poll java -Djava.nio.channels.spi.SelectorProvidersun.nio.ch.PollSelectorProvider SelectMultiplexingSocketThread 运行服务端以后观察内核所输出的系统调用函数如下 ppoll([{fd5, eventsPOLLIN}, {fd4, eventsPOLLIN}], 2, NULL, NULL, 0 fd4、5请求事件POLLIN无返回的事件类型 开启另外一个命令窗口通过 nc localhost 8090 连接服务端此时在服务端会打印出具体的客户端连接信息但观察内核文件中时它不会有任何的具体输出内容由此可见它并未与内核发生调用关系而是存储在了自身的 JVM 数组中 此时再观察 netstat -natp TCP/IP 连接信息会出现以下两条条目 此时在客户端写入一定内容观察服务端的执行过程它会先读取客户端写入的内容然后通过写事件将内容回放给客户端的窗口中如下图所示 客户端 服务端 在内核侧做出的具体处理如下图 正常状态下将 nc localhost 8090 开启的客户端正常退出再观察 TCP/IP 网络条目可以发现只有服务端侧的一条条目信息存在也就是进行了四次挥手的正常流程 测试挥手问题 在流程说明的最后客户端与服务端之间的挥手流程是正常走完的也就是说不会在服务端中存在非正常状态的客户端 sockfd 存在 若我们将源码中 client.close(); 代码进行注释然后再测试客户端关闭的一个过程 1、注释 client.close(); 客户端关闭的代码然后重新编译执行服务端代码 2、通过 nc localhost 8090 模拟客户端再次连接到服务端上. 3、关闭客户端的连接以后此时再观察 TCP/IP 条目如下所示 tcp6 0 0 ::1:50306 ::1:8090 FIN_WAIT2 - tcp6 0 0 ::1:8090 ::1:50306 CLOSE_WAIT 16838/javaTCP 需要经过四次挥手虽然在客户端这边 FIN 标记成功了但是在服务端这边还没有关闭因为服务端的 FIN 标记在客户端那一侧未作出 ACK 反应所以在 TCP/IP 条目中就会出现不完整的状态 FIN_WAIT2 | CLOSE_WAIT 信息 由此可见TCP 四次挥手的过程是两端都需要经过 FINACK 处理以后整个信息才能完全保证安全的释放 以上就会造成一个问题服务端一直持有客户端的连接信息但是这条信息是已经是没必要的它会浪费在服务端这一侧的一条「四元组源 IP:端口目标 IP:端口」信息内核中的 socketfd 就一直会被占用相同的对端服务端也就一直不能使用这个资源建立新的连接浪费的资源和名额 NIO、I/O 多路复用 在 NIO 中每次都需要遍历获取 I/O 状态每次都需要经过用户态、内核态之间的转换才能实现然后再交由给应用程序去进行 R/W 在 I/O 多路复用中通过一个系统调用可以获取到所有 I/O 状态由应用程序对有状态的 IO 进行 R/W 总结 该篇博文主要介绍的是 I/O 模型中的多路复用SELECT、POLL简要分析了 I/O 多路复用的模型通过图解分析的方式告知多路复用所带来的好处「介绍了 SELECT、POLL 函数以及它们的区别」通过实践代码的方式来分析 I/O 多路复用在系统调用中所涉及到的内核流程代码同时也当代码编写不当时会给 TCP 挥手带来的问题最后介绍了上篇 NIO 博文与 I/O 多路复用之间的区别希望能够得到你的支持感谢三连 四元组唯一源 IP、源端口、目标 IP、目标端口 愿你我都能够在寒冬中相互取暖互相成长只有不断积累、沉淀自己后面有机会自然能破冰而行 博文放在 网络 I/O 专栏里欢迎订阅会持续更新 如果觉得博文不错关注我 vnjohn后续会有更多实战、源码、架构干货分享 推荐专栏Spring、MySQL订阅一波不再迷路 大家的「关注❤️ 点赞 收藏⭐」就是我创作的最大动力谢谢大家的支持我们下文见
http://icebutterfly214.com/news/30107/

相关文章:

  • 20232309 2025-2026-1 《网络与系统攻防技术》实验四实验报告
  • 智语写作都有哪些功能?看这一篇就够了!智语写作全功能详解
  • Microsoft Activation Scripts (MAS)
  • 20232326 2025-2026-1 《网络与系统攻防技术》实验四实验报告
  • CF 2070F Friends and Pizza
  • 20232419 2025-2026-1 《网络与系统攻防技术》实验四实验报告
  • VSCode下载安装和使用教程(附安装包,适合新手)
  • 2025年博山电机供货商排行榜单
  • 20251110
  • 2025工业清洗设备及服务厂家推荐榜:聚焦凝汽器 / 换热器/空预器/板式换热器/管式换热器/空冷岛/电磁脉冲/清洗领域 四大实力品牌引领行业升级
  • 2025年推拉雨棚制造企业排行榜单
  • 行业内外架安全网平台
  • iBizModel 日历部件(PSSYSCALENDAR)模型体系详解 - 教程
  • 20232428 2025-2026-1 《网络与系统攻防技术》实验四实验报告
  • 基于DP1323EL的电动车解锁方案:超高速读写,提升电动车一键解锁体验
  • 路径遍历漏洞实战指南:5种绕过技术与自动化测试
  • 响应式编程 - reactor 初识
  • 低代码高价值场景:让设备管理真正成为企业数字化资产
  • 什么是 FFmpeg:开源免费的多媒体处理框架 - 实践
  • zed odoo lsp配置
  • 高端UI设计公司的“审美模型”:如何让界面更有记忆点?
  • GPS北斗卫星授时器:安徽京准提速时空精准网络
  • 详细介绍:【mysql】in 用到索引了吗?
  • 2025年光伏锡渣还原粉定制厂家推荐
  • SRS(simple-rtmp-server) 三Linux环境下安装SRS流媒体服务器实现视频直播推流
  • PG系列:PG数据库中分析操作系统IO是否正常
  • 098_尚硅谷_经典案例九九乘法表
  • 智慧医疗新突破:揭秘ModbusRTU转EtherCAT神器
  • 实用指南:微信PC版本4.0后小程序目录变更
  • 2025年低氮燃烧器厂家综合实力排行榜TOP10