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

wordpress社区程序seo排名关键词

wordpress社区程序,seo排名关键词,做网站主要学什么,网站 源文件目录 一.文件描述符的默认行为——阻塞IO 二.非阻塞IO 2.1.在打开文件或创建套接字时设置非阻塞模式: 2.2.在使用网络I/O接口时请求非阻塞行为: 2.3.fcntl函数 一.文件描述符的默认行为——阻塞IO 在Linux系统中,无论是通过open系统调用…

目录

一.文件描述符的默认行为——阻塞IO

二.非阻塞IO

2.1.在打开文件或创建套接字时设置非阻塞模式:

2.2.在使用网络I/O接口时请求非阻塞行为:

2.3.fcntl函数


一.文件描述符的默认行为——阻塞IO

        在Linux系统中,无论是通过open系统调用打开的文件(包括系统文件、设备文件等),还是通过socket创建的网络套接字(sock),它们对应的文件描述符(fd)默认都是阻塞的。这种阻塞行为是操作系统为了简化同步I/O操作而设计的。

        当进程尝试对一个文件描述符执行读或写操作时,如果所需的数据当前不可用(例如,读操作而缓冲区为空)或无法立即写入数据(例如,写操作而缓冲区已满或磁盘I/O繁忙),则进程将被挂起(阻塞),直到以下条件之一发生:

  1. 对于读操作:有数据可供读取,或者到达文件末尾(EOF)。
  2. 对于写操作:数据已经被成功写入到内核的缓冲区中,即使这些数据还没有被实际写入到磁盘上。

在阻塞模式下,进程需要等待这些条件成立才能继续执行,这可能会导致进程在I/O操作上花费大量时间,从而降低程序的响应性和吞吐量。

下面是一个简单的例子。

#include <iostream>  
#include <unistd.h>  
#include <string.h>  int main() {  std::cout << "This program echoes input in blocking mode. Try typing something and pressing enter.\n";  char buffer[100];  while (true) {  ssize_t bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer) - 1);  if (bytes_read > 0) {  buffer[bytes_read] = '\0'; // 确保字符串以null字符结束  std::cout << "Echo: " << buffer << std::endl;  } else if (bytes_read == 0) {  // 对于文件描述符如stdin,在阻塞模式下,read返回0通常意味着EOF(文件结束)  // 但对于stdin,这通常不会发生,除非输入被重定向自一个文件或管道,并且该文件或管道已经到达末尾  std::cout << "Unexpected end of input (this should not normally happen with stdin)." << std::endl;  break;  } else {  // read返回-1时表示发生错误  std::cerr << "Error reading input: " << strerror(errno) << std::endl;  break;  }  }  return 0;  
}

        上面这就是典型的阻塞式IO,当程序运行起来时,执行流会在read处阻塞,因为read今天读取的是0号文件描述符,也就是键盘文件上的数据,只要我不从键盘上输入数据的话,read就会一直阻塞,此时进程会被操作系统挂起,直到硬件设备键盘上有数据时,进程才会重新投入CPU的运行队列,当我们输入数据后,可以立马看到进程显示出了echo回应的结果,同时进程又立马陷入阻塞,等待我进行下一次的输入数据,这样的IO方式就是典型的阻塞式,同时也是最常用,最简单的IO方式。

        为了解决这个问题,Linux提供了非阻塞I/O(Non-blocking I/O)和异步I/O(Asynchronous I/O)等机制。通过设置文件描述符为非阻塞模式,进程可以在I/O操作无法立即完成时立即返回一个错误(通常是EAGAINEWOULDBLOCK),而不是被挂起。这样,进程就可以继续执行其他任务,而不会因等待I/O操作而阻塞。

        对于网络套接字,除了设置非阻塞模式外,还可以使用I/O多路复用技术(如select、poll、epoll)来同时监视多个文件描述符的状态,从而在不增加线程或进程数量的情况下处理多个并发连接。这些技术允许进程在单个线程中高效地管理多个I/O操作,提高了程序的性能和可扩展性。

二.非阻塞IO

在Linux操作系统中,关于设置文件描述符(fd)为非阻塞模式的方式主要有两种。下面是对这两种主要方式的准确描述:

2.1.在打开文件或创建套接字时设置非阻塞模式:

  1. 对于文件(包括设备文件),通常不建议也不常见将其设置为非阻塞模式,因为文件I/O操作(如读、写)通常是同步完成的,且没有像网络I/O那样的等待状态。但是,如果您确实需要对文件描述符设置非阻塞模式(例如,对于管道、FIFO或某些特殊类型的文件),可以在使用open系统调用时,在flags参数中包含O_NONBLOCK标志。
  2. 对于套接字,由于套接字是通过socket系统调用创建的,而不是open,因此您不能在socket调用时直接设置O_NONBLOCK。但是,您可以在socket调用之后,使用fcntl函数和F_SETFL命令来修改套接字文件描述符的标志,以包含O_NONBLOCK。
 // 创建套接字  int sockfd = socket(AF_INET, SOCK_STREAM, 0);  // 设置套接字为非阻塞模式  fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) | O_NONBLOCK); 

注意:像fcntl这样的方式,无论对于系统文件还是网络套接字都是完全适用的。

2.2.在使用网络I/O接口时请求非阻塞行为:

        对于网络套接字,虽然您已经在套接字级别设置了非阻塞模式,但在某些情况下,您可能还想在特定的send、recv等I/O调用中请求非阻塞行为,以确保该调用不会因等待数据而阻塞。这可以通过在调用这些函数时包含MSG_DONTWAIT标志来实现。但是,请注意,如果套接字已经设置为非阻塞模式,那么即使没有指定MSG_DONTWAIT,这些调用也不会阻塞。

MSG_DONTWAIT主要用于在套接字处于阻塞模式时,临时请求非阻塞行为。

 // 套接字已经设置为非阻塞模式,但显式使用MSG_DONTWAIT也可以  ssize_t n = recv(sockfd, buf, len, MSG_DONTWAIT);  if (n == -1 && errno == EAGAIN) {  // 处理非阻塞情况下没有数据可读的情况  } 

        然而,在实际应用中,当您希望套接字以非阻塞方式工作时,通常会在套接字创建后立即使用fcntl设置其非阻塞模式,并在后续的网络I/O调用中不再需要显式地指定MSG_DONTWAIT(除非您有特定的理由需要在某些调用中临时恢复阻塞行为)。

        因此,总结来说,设置文件描述符为非阻塞模式的主要方式是通过fcntl和O_NONBLOCK标志(对于套接字和某些特殊类型的文件),而不是通过open的O_NONBLOCK选项(因为套接字不是通过open创建的),并且MSG_DONTWAIT是在网络I/O调用中请求非阻塞行为的额外选项,但它不是设置文件描述符非阻塞模式的独立方法。

2.3.fcntl函数

        当涉及到在Linux中对文件进行控制和管理时,fcntl(file control)函数是一个强大的工具。它提供了一种灵活的方式来执行各种文件操作,从修改文件属性到锁定文件,甚至是改变文件的行为。本文将深入探讨fcntl函数的用法、参数和示例,帮助读者更好地了解如何利用这个功能强大的API来操作文件。

        fcntl函数是Linux系统中用于执行各种文件控制操作的系统调用之一。它可以用于修改文件描述符的属性,如文件状态标志(file status flags)、文件描述符标志(file descriptor flags)、文件锁(file locks)以及其他的一些操作。fcntl函数提供了对文件或文件描述符进行底层控制的接口,使得开发者可以更精细地管理文件的行为。

fcntl函数的原型和参数

在C语言中,fcntl函数的原型如下:

#include <fcntl.h>int fcntl(int fd, int cmd, ... /* arg */);
  1. fd 是要操作的文件描述符。
  2. cmd 是控制操作的命令。
  3. arg 是与命令相关联的可选参数。

fcntl函数的cmd参数决定了具体执行的操作类型,常见的一些操作包括:

  1. F_GETFL:获取文件描述符的状态标志。
  2. F_SETFL:设置文件描述符的状态标志。
  3. F_GETLK:获取文件锁。
  4. F_SETLK:设置或释放文件锁。
  5. F_SETLKW:阻塞地设置或释放文件锁。

文件状态标志(File status flags)

  1. O_RDONLY:只读打开。
  2. O_WRONLY:只写打开。
  3. O_RDWR:读写打开。
  4. O_APPEND:追加写入。
  5. O_CREAT:如果文件不存在则创建文件。
  6. O_EXCL:与O_CREAT一起使用,如果文件存在则报错。
  7. O_TRUNC:如果文件存在且为只写或读写,则将其长度截断为0。

文件描述符标志(File descriptor flags):

  • FD_CLOEXEC:在exec执行期间关闭文件描述符。

其他标志:

  • O_NONBLOCK:非阻塞模式,用于文件描述符,使得对文件的读写操作不会阻塞进程。
  • O_SYNC:使得每次write都等到物理 I/O 操作完成后才返回。
  • O_DIRECTORY:如果文件名是目录,则打开失败。
  • O_DSYNC:等待物理 I/O 数据完成,不等待文件属性更新。
  • O_NOATIME:不更新访问时间戳。
  • O_NOCTTY:如果设备是终端,不将其分配为控制终端。

下面是一个简单的将文件描述符设置为非阻塞的例子

#include <iostream>  
#include <unistd.h>  
#include <fcntl.h>  
#include <errno.h>  
#include <string.h>  int main() {  std::cout << "This program echoes input in non-blocking mode. Try typing something and pressing enter.\n";  char buffer[100];  while (true) {  ssize_t bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer) - 1);  if (bytes_read > 0) {  buffer[bytes_read] = '\0'; // 确保字符串以null字符结束  std::cout << "Echo: " << buffer << std::endl;  } else if (bytes_read == 0) {  // 对于文件描述符如stdin,read返回0通常不表示结束,但在某些特殊情况下(如管道关闭)可能会发生  std::cout << "Unexpected end of input (this should not happen with stdin)." << std::endl;  break;  } else {  // read返回-1且errno被设置时表示发生错误  if (errno == EAGAIN || errno == EWOULDBLOCK) {  // 这是非阻塞模式下期望的行为,表示没有数据可读  std::cout << "No data available. Waiting...\n";  sleep(1); // 等待一秒后再次尝试  } else {  // 处理其他类型的错误  std::cerr << "Error reading input: " << strerror(errno) << std::endl;  break;  }  }  }  return 0;  
}

我们看到它阻塞了。

 接下来我将使用fcntl函数来将fd的属性改为非阻塞 

#include <iostream>  
#include <unistd.h>  
#include <fcntl.h>  
#include <errno.h>  
#include <string.h>  /**  * 将指定的文件描述符设置为非阻塞模式。  *  * @param fd 需要设置为非阻塞模式的文件描述符。  */  
void set_no_block(int fd) {  // 尝试获取文件描述符的当前标志(flags)  int flags = fcntl(fd, F_GETFL, 0);  // 检查fcntl调用是否失败  if (flags == -1) {  // 如果失败,则打印错误消息并返回  perror("fcntl");  // 使用perror打印错误信息,它会自动添加"fcntl: "前缀  return;  }  // 使用OR操作将O_NONBLOCK标志添加到现有的flags中  // 这样做的目的是保留文件描述符的其他标志不变,只添加非阻塞特性  fcntl(fd, F_SETFL, flags | O_NONBLOCK);  // 注意:这里没有检查fcntl的返回值,因为即使设置失败,也可能不会立即影响程序的行为  // 在实际使用中,可能需要根据需要添加错误处理逻辑  
}  int main() {  std::cout << "This program echoes input in non-blocking mode. Try typing something and pressing enter.\n";  // 将标准输入设置为非阻塞模式  set_no_block(STDIN_FILENO); // 使用STDIN_FILENO代替0,更具可读性  char buffer[100];  while (true) {  ssize_t bytes_read = read(STDIN_FILENO, buffer, sizeof(buffer) - 1);  if (bytes_read > 0) {  buffer[bytes_read] = '\0'; // 确保字符串以null字符结束  std::cout << "Echo: " << buffer << std::endl;  } else if (bytes_read == 0) {  // 对于文件描述符如stdin,read返回0通常不表示结束,但在某些特殊情况下(如管道关闭)可能会发生  std::cout << "Unexpected end of input (this should not happen with stdin)." << std::endl;  break;  } else {  // read返回-1且errno被设置时表示发生错误  if (errno == EAGAIN || errno == EWOULDBLOCK) {  // 这是非阻塞模式下期望的行为,表示没有数据可读  std::cout << "No data available. Waiting...\n";  sleep(1); // 等待一秒后再次尝试  } else {  // 处理其他类型的错误  std::cerr << "Error reading input: " << strerror(errno) << std::endl;  break;  }  }  }  return 0;  
}

注意:

  1. F_GETFL操作用于获取文件描述符的当前标志,这些标志包括文件的访问模式(如只读、只写、读写)和文件状态标志(如同步、异步、非阻塞等)。F_SETFL操作用于设置文件描述符的标志。
  2. O_NONBLOCK是一个标志,用于指示文件描述符应处于非阻塞模式。在非阻塞模式下,如果操作(如读取或写入)不能立即完成,则调用将返回一个错误,而不是阻塞等待操作完成。这对于需要处理多个输入源或避免阻塞的应用程序非常有用。
  3.  先通过F_GETFL选项获取原有文件描述符的标志位,然后再通过F_SETFL选项将原有的标志位与O_NONBLOCK按位或之后,再重新设置回文件中。这样就可以将文件描述符设置为非阻塞了。
  •  非阻塞IO时,read的返回结果是-1,这样合理吗?

        当在非阻塞模式下调用read函数,并且底层没有数据时,read会返回-1,并设置errnoEAGAINEWOULDBLOCK(这两个错误码在大多数系统上可互换,表示资源暂时不可用)。这是非阻塞IO的一种标准行为,用于告诉调用者当前没有数据可读,而不是表示read函数本身出现了错误。

        底层没有数据,这算错误吗?其实这并不算错误,只不过当底层没有数据时,read以错误的方式返回了,但我们该如何区分read接口是真的调用失败了(比如read读取了一个不存在的fd),还是仅仅底层没有数据罢了,当然通过read的返回值我们是无法区分的,因为read在这两种情况下都返回-1,但可以通过错误码来区分,当非阻塞IO返回时,如果是底层没有数据,错误码会是EWOULDBLOCK或EAGAIN,如果read是真的出错调用了,会有相对应的错误码。

        因此,在处理非阻塞IO时,一种常见的做法是在read返回-1时检查errno,并根据errno的值来决定下一步的操作。如果errno表示资源暂时不可用(EAGAINEWOULDBLOCK),则程序可能会选择等待一段时间后再次尝试读取,或者执行其他任务。如果errno表示真正的错误(如EBADF),则程序应该采取适当的错误处理措施。

在Linux系统中,EAGAINEWOULDBLOCK是两个常见的错误码,它们通常用于指示资源暂时不可用的情况。具体来说:

  1. EAGAIN:这个错误码代表“Try again”(再试一次),意味着请求的操作暂时无法完成,但之后可能会成功。在网络编程中,EAGAIN经常出现在非阻塞套接字的读写操作中,表示暂时没有数据可读或数据无法立即写入。在文件操作中,如果文件描述符被设置为非阻塞模式,并且请求的操作不能立即完成(例如,读取时文件指针已经到达文件末尾,或者写入时磁盘空间不足但系统决定不等待),那么也会返回EAGAIN

  2. EWOULDBLOCK:这个错误码在某些情况下与EAGAIN可互换,同样表示资源暂时不可用。然而,在某些系统或特定的上下文中,EWOULDBLOCK可能更具体地用于指示某个操作被阻塞了,因为它会等待某个条件(如数据到达)变为真,但在非阻塞模式下,这个等待被阻止了。在大多数情况下,EAGAINEWOULDBLOCK可以视为同义词,尤其是在处理非阻塞I/O时。

怎么样?是不是很神奇?

http://www.ritt.cn/news/2226.html

相关文章:

  • 电子工程网络网络推广优化培训
  • 优书网有官方app吗杭州网站优化咨询
  • 网站开发容易找工作吗要看网的域名是多少
  • 南宁品牌网站建设公司seo教学
  • 政府网站建设要求自查成人职业培训机构
  • 外贸电子网站百度账号中心官网
  • 公司网站中文域名收费吗排名优化网站建设
  • 网站建设费用能否计入广告费郑州竞价托管公司哪家好
  • 网站主体备案信息查询重庆关键词优化
  • 网站会员权限潍坊今日头条新闻
  • 普通网站 用多说企业网络营销方法
  • 网站建设越来越难做百度资源共享
  • 外贸公司出口退税申报流程北京网优化seo优化公司
  • 网站设计 色彩免费seo软件推荐
  • wordpress指定标签不同样式seo刷排名软件
  • 郑州制作网站电话133排名优化公司哪家好
  • 黄页88官网网站如何优化
  • 大型b2b电子商务平台开发外贸网站优化公司
  • 哪个做简历的网站比较好今日新闻7月1日
  • 如何查看网站模板学技术包分配的培训机构
  • 模板免费网站百度广告官网
  • 连云港建设部网站六种常见的网络广告类型
  • 做商务网站需要什么资料推广项目网站
  • 网站建设有几种seo外包优化服务商
  • 网络平台维护是什么工作百度sem优化师
  • 天津西青区邮政编码seo推广论坛
  • 娱乐新闻做的好的网站关键词搜索查询
  • 成交功能网站b站好看的纪录片免费
  • 张家界seo优化方案seo软件下载
  • 义乌商城集团的网站建设公司网络搭建