1 strict-origin-when-cross-origin

strict-origin-when-cross-origin 是一种Referrer策略,是浏览器用于保护用户隐私的一种安全策略。Referrer是HTTP请求头的一部分,会在用户访问一个网站时,将用户来源的信息发送给目标网站。而 strict-origin-when-cross-origin 策略的作用就是在跨域请求时,只将源站点的Referrer信息发送给目标站点,而不会将路径、参数等信息发送出去,从而保护用户的隐私。
具体来说,如果一个页面的地址为 origin-a.com ,其中包含一个链接指向 origin-b.com ,当用户点击该链接时,浏览器会在 HTTP 请求头中带上 Referrer 头字段,该字段会告诉 origin-b.com 这个请求来自于 origin-a.com。如果使用 strict-origin-when-cross-origin 策略,那么只有在请求头中的 Referrer 和当前页面的域名相同的时候,才会将 Referrer 发送给目标站点 origin-b.com,否则不会发送 Referrer。
这种策略的作用是防止一些恶意网站通过 Referrer 信息来追踪用户的行踪路径,保护用户的隐私安全。同时,该策略也不会对网站的功能产生太大的影响,因为对于同源站点的请求,仍然可以正常发送 Referrer 信息,不会影响网站的正常运行。

解决办法:换个端口号,有些端口号不能使用

2 同步非阻塞 IO 模型中,应用程序会一直发起 read 调用,等待数据从内核空间拷贝到用户空间的这段时间里,线程依然是阻塞的,直到在内核把数据拷贝到用户空间。相比于同步阻塞 IO 模型,同步非阻塞 IO 模型确实有了很大改进。通过轮询操作,避免了一直阻塞。

在同步非阻塞IO模型中,应用程序使用系统调用(如 read())从内核空间读取数据,但是这些调用是非阻塞操作,即调用会立即返回,而不是阻塞等待读取数据。当没有数据可用时,read() 将返回一个错误代码EAGAIN或EWOULDBLOCK,并且应用程序可以继续执行其他操作而不是等待数据的错误返回。

然而,当有数据可用时,read()函数会开始从内核空间向用户空间拷贝数据,这个过程是阻塞的,这意味着线程会等待,直到数据被拷贝到用户空间后才能继续执行。因此,即使使用了非阻塞IO,线程还是会在数据拷贝的阶段被阻塞。

为了解决阻塞问题,可以使用异步IO来取消阻塞。在异步IO中,当读取操作完成时,内核会通知应用程序,而不是让应用程序等待数据被拷贝。这意味着应用程序可以在等待数据的同时执行其他操作,提高了系统的并发性能和吞吐量。

3 同步阻塞 IO 模型中,应用程序发起 read 调用后,会一直阻塞,直到内核把数据拷贝到用户空间。

在同步阻塞IO模型中,当应用程序调用read()函数从内核空间读取数据时,操作系统内核会将应用程序阻塞,直到所有数据被拷贝到用户空间。当应用程序执行read()调用时,线程会进入阻塞状态。它会一直阻塞,直到内核将所有请求的数据从设备读取并将其移动到内核缓冲区,然后再将缓冲区中的数据复制到应用程序提供的缓冲区中。

因此,同步阻塞IO模型是一种较为基本的IO操作方式,它的缺点在于它会占用调用线程,不会进行其他工作,直到数据读取完成。在高并发场景下,同步阻塞IO性能往往比较低效,因为应用程序需要等待数据读取和拷贝,这会导致整个进程的性能下降。

4 BIO和NIO有什么区别吗

同步阻塞IO和NIO的主要区别在于IO操作的方式和处理方式不同。

在同步阻塞IO模型中,当一个IO操作发生时,内核会将应用程序线程阻塞,直到IO操作完成。这意味着,在同一时间只能处理一个IO操作,如果有多个 IO 操作需求,就需要启动多个线程来处理。这种模型在并发场景下效率不高,因为每个线程之间的切换成本很高。

相比之下,NIO使用的是非阻塞IO模型,即应用程序向内核发起IO操作时并不会被阻塞,而是立即返回,等待内核就绪后再回来执行相应的操作。这种模型可以支持一个线程处理多个IO操作。NIO将IO转化为事件驱动模型,使得可以在单个线程内处理多个IO操作,提高系统的并发处理能力。NIO在处理高并发网络时有很好的性能优势。

此外,NIO还提供了一些功能,如缓冲区、通道和Selector,用于在应用程序和底层网络传输之间进行高效的数据传输,这使得NIO更加灵活、可扩展和高性能。

下面是一个简单的使用Java NIO读取文件的示例代码:

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

public class NIOFileRead {
    public static void main(String[] args) throws IOException {
        Path path = Paths.get("test.txt");
        FileChannel fileChannel = FileChannel.open(path);
        ByteBuffer buffer = ByteBuffer.allocate(1024);
        while(fileChannel.read(buffer) > 0) {
            buffer.flip();
            while(buffer.hasRemaining()) {
                System.out.print((char) buffer.get());
            }
            buffer.clear();
        }
        fileChannel.close();
    }
}

在上面的代码中,我们使用FileChannel和ByteBuffer API,打开文件,从文件通道读取数据,并将其输出到控制台。实际上,NIO在Java中还有很多其他用法场景。

5 同步非阻塞 IO 模型中,应用程序会一直发起 read 调用,等待数据从内核空间拷贝到用户空间的这段时间里,线程依然是阻塞的,直到在内核把数据拷贝到用户空间。相比于同步阻塞 IO 模型,同步非阻塞 IO 模型确实有了很大改进。通过轮询操作,避免了一直阻塞。 这样一直轮询调用和BIO有什么区别吗

在同步非阻塞IO模型中,虽然应用程序没有被阻塞,但它需要不断轮询以检查IO操作是否已就绪并读取数据。在同步非阻塞IO模型中,应用程序无需等待而可以处理其他事情,但是它仍然需要主动地查看操作结果,所以它仍然会跑一些代码。

相比之下,同步阻塞IO模型中,在进行IO操作时,应用程序将一直处于阻塞状态,直到内核完成IO操作并返回结果。在这种情况下,应用程序没有任何处理,它只是等待结果的返回。这种模型非常慢,因为它浪费了大量的时间在等待上。

因此,同步非阻塞IO模型是在保持IO操作的情况下,增加了轮询操作,以便在内核返回操作结果之前,允许应用程序继续运行。但是,需要注意的是,这种模型伴随着对CPU的不断轮询,增加了CPU负担。

短暂地说,同步非阻塞IO模型是比较好的模型,因为它在允许轮询操作的同时保持了IO操作,允许应用程序可以处理其他事情,从而提高了系统性能和吞吐量。相比之下,BIO模型立即被阻塞,无论是发起IO操作还是处理其他事情。

6 NIO是一直轮询等待IO操作就绪,同时也可以处理其他事情

NIO允许在IO操作未准备好时继续执行其他任务,这是因为NIO使用了非阻塞IO模型(Non-blocking IO)。在NIO中,当您向通道中写入或从通道中读取数据时,通道将立即返回控制,而不是阻塞线程等待完整的IO操作完成。这意味着您可以同时进行其他操作,而不必等待IO操作完成。但是您需要使用轮询机制不断查询数据是否准备就绪,这样会消耗CPU资源,因此NIO适用于IO密集型场景,在处理并发IO操作时具有优越性。

7 为什么NIO轮询会消耗CPU

在NIO编程中,轮询机制本质上是内核态和用户态之间不断切换的过程。当您使用NIO时,您需要使用一个线程不断地调用Selector.select()方法来返回所有已准备就绪的IO操作的数据,同时在内核态和用户态之间不断地切换。因此,频繁的轮询可能会消耗大量的CPU资源,因为当系统没有IO事件时,NIO线程仍然需要持续地进行轮询操作。
为了减少CPU的消耗,在应用中可以使用较小的超时值调用Selector.select(timeout)来使线程在一段时间后超时。这种方法可以减少轮询的次数,并且可以使线程更有效地使用CPU。此外,可以使用多个选择器,将不同的通道分配给它们,并在发现事件后将它们分发到不同的线程中以减轻单个线程的负担。

8 NIO这个轮询线程是单独设置的吗

是的,当您使用NIO编程时,必须为每个正在运行的应用程序分配一个专用的I/O线程,该线程将执行Selector的循环轮询处理,以便及时检测到已经就绪的I/O操作。实际上,您可以在应用程序中创建一个或多个线程池,将相应的任务分配给它们,并通过配置不同数量的线程来调整应用程序的性能。在使用NIO时,还可以使用多个Selector来同时处理输入和输出事件的选择器,以便更好地控制I/O操作。需要注意的是,I/O线程的数量应根据应用程序的实际情况进行调整,以避免线程数量过多或过少而导致的不必要的浪费或不足。

9 NIO是基于IO多路复用吗

是的,NIO 是基于 IO 多路复用的。Java NIO(New I/O)包含了一些对 I/O 操作的改进,它提供了非阻塞(以 NIO 为代表,在 Java 中称为 NIO 或 New IO)和多路复用技术来处理 I/O 操作,可以针对网络和文件系统进行优化。NIO 中引入了 Channel(通道)和 Buffer(缓冲区)两个主要的概念,并提供了 Selector(选择器)实现多路复用的机制。

与传统的阻塞 I/O 不同,NIO 基于 SelectableChannel,这种 Channel 不会直接阻塞在 I/O 操作上,而是可以一次性同时监听多个 Channel,只有当它们中的某一个 Channel 有 I/O 操作的时候再去处理对应的 I/O 事件。这样可以大大减少线程数目和线程之间的切换,提高了系统的并发处理能力。多路复用机制可以让单个线程处理多个并发连接,从而提高了服务器的吞吐量和性能。因此,当需要同时处理多个连接时,使用 NIO 可以比传统的 I/O 更高效。

10 介绍一下IO多路复用

I/O多路复用指的是一种通过单个线程管理多个I/O请求的机制。具体来说,它允许一个线程监视多个Socket通道,并且只有在至少一个通道准备好进行I/O操作时,该线程才会开始执行实际的I/O操作。因此,I/O多路复用能够大幅度减少线程数量,提高系统的并发性能,也能够更有效地使用系统资源。

常见的I/O多路复用技术有三种:select、poll和epoll。这些技术都使用同一个系统调用来注册一组文件描述符,并在其中一个描述符上发生I/O事件时通知应用程序。它们之间的区别在于在高负载情况下的性能表现不同。

  • Select:使用轮询方式遍历所有注册的文件描述符集合,因此遇到高负载时,性能很差,可使用的文件描述符数量也有限制,一般上限为1024。所以,Select在高并发场景并不是最优选择。
  • Poll:解决了Select遇到高负载时性能差的问题,但是可使用的文件描述符数量仍有上限。它的工作原理与Select类似,仍然需要轮询遍历所有已注册的文件描述符。
  • Epoll:解决了Select和Poll的一些限制,可以支持数十万个文件描述符的并发。它使用了回调函数通知应用程序已就绪的描述符,并且可以使用较小的内核空间缓冲区来处理大量的I/O事件,因此EPoll可以更有效地处理高连接数场景。

总的来说,在高并发网络编程中,使用I/O多路复用会明显提升系统的并发能力和性能表现。

11 详细介绍一下AIO

AIO(Asynchronous IO),也称为异步非阻塞IO,是一种基于事件和回调机制的IO操作方式,与传统的同步阻塞式IO不同。

在传统的同步阻塞IO中,当一个IO请求发出后,线程会一直等待IO操作完成才会继续执行后续的处理,这样会造成线程被阻塞,浪费CPU资源。而在AIO中,当一个IO请求发出后,线程不会等待IO操作完成,而是可以继续执行其他的任务,当IO操作完成后,系统会通过回调函数通知程序进行处理。这样,AIO可以让一个线程同时处理多个IO请求,而不会出现因等待IO操作而导致CPU资源浪费的情况。

AIO提供了两个核心类:AsynchronousServerSocketChannel和AsynchronousSocketChannel。当有新的连接进来时,我们可以通过AsynchronousServerSocketChannel接收连接并返回AsynchronousSocketChannel对象用于后续的读写操作。在进行读写操作时,我们可以使用AsynchronousSocketChannel的read和write方法,以及CompletionHandler回调函数来处理读写就绪的事件。在AIO中,读写就绪事件的处理和线程的关系由操作系统内部完成,无需开发者关心。

总的来说,使用AIO可以实现较高的并发性能和资源使用效率。但是AIO的缺点是其对应用程序的编写和管理都有一定的要求,因此在选择IO模型时应根据具体业务场景进行选择。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐