freebsd高级I/O,kevent的资料很详细

C++高性能Web服务器:从阻塞I/O到事件驱动架构的实践 在网络编程中,I/O模型是决定服务性能的核心。传统的阻塞式I/O模型为每个连接分配独立线程,在并发量上升时面临资源消耗大、可扩展性差的问题。其原理是线程在数据未就绪时会进入等待状态,导致CPU空闲和频繁的上下文切换。为了解决这一瓶颈,非阻塞I/O与事件驱动模型应运而生,通过I/O多路复用技术(如kqueue、epoll)实现单线程管理大量连接,极大地提升了资源利用率和系统吞吐量。这一技术价值在于能够以极低的资源开销支撑数万甚至数十万的并发连接,特别适用于高并发的网络服务场景,如实时通信、API网关和微服务架 阅读详情
 FreeBSD系统编程(6)
作者:FinalBSD  出处:Unix爱好者家园unix-cd.com  更新时间: 2006年05月12日 

 


翻译:雨丝风片@chinaunix.net



6.1 高级I/O和进程资源

正如我们在前面章节中看到的,程序可以同时打开多个文件描述符。这些文件描述符并不一定就是文件,还可以是fifo、pipe或者socket。于是,如何复用这些打开的描述符就很重要了。例如,考虑一个简单的邮件阅读程序,比如pine。它显然应当允许用户在读写email的同时也能去检查是否有新邮件。这就意味着在任一给定时刻都至少能够接收两个来源的输入:一个来源是用户,另一个是用来检查新邮件的描述符。处理描述符的复用是个复杂的问题。一种方法是把所有打开的描述符都标记为非阻塞的(O_NONBLOCK),然后在它们之中循环,直到找到一个可以进行I/O操作的描述符为止。这种方法的问题是程序会一直在循环,如果长时间内没有I/O可用,进程就会一直占据CPU。当有多个进程在一组很少的描述符上循环时,你的CPU的负载就会恶化。

另一种方法就是设置信号处理器去捕获I/O变为可用的事件,然后就让进程进入休眠状态。如果你只打开了少量的描述符,而且并不经常请求I/O的话,这种方法从理论上看倒是不错。由于进程已经休眠,就不会再占用CPU,仅当I/O可用时它才恢复执行。然而,这种方法的问题在于信号处理的开销有点大。比如一个web服务器,每分钟收到100个请求,那就几乎一直都在捕获信号。每秒钟捕获上百个信号的开销是相当大的,不单是进程,对于内核发送信号的开销而言也是一样的。

到目前为止,我们看到的两种选择都有限制,效率也不高,它们需要解决的共同问题就是进程需要知道I/O究竟什么时候能用?然而,这个信息实际上只有内核才能事先知道,因为是内核在最终处理系统中的所有打开的描述符。例如,当一个进程通过fifo向另一个进程发送数据的时候,发送进程会调用write,这是一个系统调用,因此会进入内核。在发送方的write系统调用执行完毕之前接收方对此是一无所知的。于是就引出了一个更好的复用文件描述符的方法:由内核来替进程管理描述符。换句话说,就是把一个打开描述符的链表发送给内核,然后等待,直到内核发现某个或多个描述符已经准备好了或者已经超时了为止。

这就是select()、poll()和kqueue()接口采用的方法。通过这些接口,内核就会管理文件描述符,当I/O可用时就去唤醒进程。这些接口巧妙地处理了上述问题。进程不必再在打开的文件描述符中循环,也不必再去设置信号了。但进程在使用这些函数的时候还是会产生一点小问题。这是因为I/O操作是在从这些接口返回之后才去执行的。所以它至少需要两个系统调用才能完成其操作。例如,你的程序有两个用于读的描述符。你对它们使用select,然后等待它们直至有数据可读。这就需要进程首先调用select,在select返回之后,就对该描述符调用read。更妙的是,你还可以对所有打开的描述符执行一个整体的read。一旦其中有某个描述符准备好读之后,read就会返回,并把数据放在缓冲区中,同时还会给出一个标识,用来指示这个数据是从哪个描述符读进来的。

6.2 select

我首先要讲的接口是select()。格式如下:

 
int  select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,  struct timeval *timeout);
传给select的第一个参数已经造成了多年的混乱。nfds参数的正确用法是把它设成文件描述符的最大值加1。换句话说,如果你有一组文件描述符{0,1,8},nfds参数就应当被设置成9,因为你的描述符的最大值为8。有些人错误地以为这个参数的意思是文件描述符的总数加1,对于我们的例子而言就是4。记住,一个文件描述符只是一个整数而已,所以你的程序就需要指出你所想要在其上select的最大的描述符值。

select接下来会按顺序针对所有尚未完成的读、写以及异常条件检查其余的三个参数,readfds、writefds和exceptfds。(详细信息请参见man(2) select)。注意,如果readfds、writefds和execptfds中没有设置描述符,那么传给select的对应参数应当被设置成NULL。

readfds、writefds和execptfds参数通过以下4个宏进行设置。

FD_ZERO(&fdset);

FD_ZERO宏用来对指定的描述符集合中的bit进行清零。有一点需要特别注意:只要使用select,就应当调用这个宏;否则select的行为将是不可预知的。

FD_SET(fd, &fdset);

FD_SET宏用于向一组激活的描述符中添加一个描述符。

FD_CLR(fd, &fdset);

FD_CLR宏用于从一组激活的描述符中删除一个描述符。

FD_ISSET(fd, &fdset);

FD_ISSET宏是在select返回之后使用的,用于测试某个描述符是否已准备好进行I/O操作。

select的最后的参数是一个超时值。如果超时值被设置为NULL,则对select的调用将以不确定的方式被阻塞,直至某个操作已准备好为止。如果你需要一个确定的超时时间,那么超时值就得是一个非空的timeval结构体。timeval结构体如下:

 
  struct timeval {
      long    tv_sec;         /* seconds */
      long    tv_usec;        /* microseconds */
  };
如果select调用成功,将返回准备好的描述符的数目。如果select因为超时而返回,则返回值为0。如果有错误发生,则返回-1,同时会相应地设置errno。

6.3 poll

我们在这里对I/O的讨论主要是针对BSD的。System V支持一种特殊类型的I/O,即所谓的STREAMS。和socket一样,STREAMS也具有优先级属性,这种属性有时也被成为数据带。数据带可用来给STREAMS中的特定数据设置较高的优先级。BSD最初并不支持这一特性,不过有些人添加了System V仿真功能,可以对某些类型提供支持。由于我们并不关注System V,因此我们只会引用数据带或数据优先级带的概念。详细信息请参见System V STREAMS。

poll函数和select很相似:

 
  int  poll(struct pollfd *fds, unsigned int nfds, int timeout);
和原产于BSD的select不同,poll是由System V Unix创建的,在早期的BSD版本中并不支持它。目前主流BSD系统中都已经支持poll了。

和select相似,poll也是在一组给定的文件描述符上进行复用。在指定这些描述符的时候,你必须使用一个结构体数组,其中每个结构体代表一个文件描述符。和select相比,poll的好处就是你可以判断一些很罕见的条件,而select则无法做到。这些条件是POLLERR、POLLHUP和POLLNVAL,我们稍后讨论。尽管对于选择select还是poll的问题已经有了相当多的讨论,但这在很大程度上还是取决于你的个人爱好。poll所使用的结构体是pollfd结构体,如下:

 
  struct pollfd {
      int     fd;             /* which file descriptor to poll */
      short   events;         /* events we are interested in */
      short   revents;        /* events found on return */
  };
fd

fd成员用于指定你想要poll的文件描述符。如果你想删除一个描述符,那就把那个描述符的fd成员设置成-1。通过这种方法,你可以避免对整个数组进行混洗,同时还可以清除revents成员中列出的所有事件。

events, revents

events成员是一个bit掩码,用于指定针对指定描述符所关心的事件。revents成员也是一个bit掩码,但它的值是由poll设置的,用于记录在指定描述符上发生的事件。这些事件的定义如下:

 
  #define POLLIN          0x0001
POLLIN事件表明你的程序将选择该描述符上的可读数据事件。注意,此处的数据不包括高优先级数据,比如socket上的带外数据。

 
  #define POLLPRI         0x0002
POLLPRI事件表明你的程序准备选择该描述符上的任何高优先级事件。

 
  #define POLLOUT         0x0004
  #define POLLWRNORM      POLLOUT
POLLOUT和POLLWRNOMR事件表明你的程序想知道什么时候可以对一个描述符执行写操作了。在FreeBSD和OpenBSD上这两个事件是相同的;你可以在你的系统头文件(/usr/include/poll.h)中查证这一点。从技术角度来说,它们之间的区别在于POLLWRNOMR仅当数据优先带等于0的时候才去检测是否可以进行写操作。

 
  #define POLLRDNORM      0x0040
POLLRDNORM事件表明你的程序准备选择该描述符上的常规数据。注意,在某些系统上,这个事件指定的操作和POLLIN完全一样。但在NetBSD和FreeBSD上,这个事件和POLLIN并不相同。同样,请去查看你的系统头文件(/usr/include/poll.h)。严格地说,POLLRDNORM仅当数据优先带等于0的时候采取检测是否可以进行读操作。

 
  #define POLLRDBAND      0x0080
POLLRDBAND事件表明你的程序想知道什么时候能够以一个非0的数据带值从该描述符读数据。

 
  #define POLLWRBAND      0x0100
POLLWRBAND事件表明你的程序想知道什么时候能够以一个非0的数据带值向该描述符写数据。

专用于FreeBSD的选项

下面的选项是专用于FreeBSD的,知道的和使用的人都不是太多。但它们还是值得提一下,因为它们可以提供更多的灵活性。这些都是新的选项,poll并不保证能够检测这些条件,而且它们只能用于UFS文件系统。如果你的程序需要检测这些类型的事件,那最好使用kqueue接口,我们将在稍后介绍。

 
  #define POLLEXTEND      0x0200
如果文件已经被执行,则设置POLLEXTEND事件。

 
  #define POLLATTRIB      0x0400
如果有任一文件属性发生改变,则设置POLLATTIB事件。

 
  #define POLLNLINK       0x0800
如果文件被重命名、删除或解除链接,则设置POLLNLINK事件。

 
  #define POLLWRITE       0x1000
如果文件内容被修改,则设置POLLWRITE事件。

下面的事件并不是pollfd events成员的有效标志,poll也将忽略它们。它们是在pollfd revents中返回的,用于表明发生了某个事件。

 
  #define POLLERR         0x0008
POLLERR事件表明有错误发生。

 
  #define POLLHUP         0x0010
POLLHUP表明在对应的STREAMS上发生了挂起事件。POLLHUP和POLLOUT是互斥事件,因为一个发生了挂起的STREAMS就不再是可写的了。

 
  #define POLLNVAL        0x0020
POLLNVAL表明对poll的请求是无效的。

poll的最后一个参数是超时值。可以通过这个参数告诉poll一个以微秒为单位的超时值。如果把超时值设置为-1,poll就会阻塞,直至所请求的事件发生为止。如果超时值设置为0,则poll将立即返回。

如果对poll的调用成功,则返回一个正整数。这个正整数的值表示有多少个描述符发生了事件。如果超时,poll将返回0。如果有错误发生,poll则会返回-1。

6.4 kqueue

到目前为止,poll和select已经是相当不错的复用文件描述符的方法了。但为了使用这两个函数,你需要创建一个描述符的链表,然后把它们发送给内核,在返回的时候又要再次查看这个链表。这看上去有点效率低下。一个更好一些的模型是把描述符链表交给内核,然后就等待。一旦有某个或多个事件发生,内核就把一个只包含有发生了事件的描述符的链表通知给进程,由此避免了每次函数返回的时候都要去遍历整个链表。尽管对于只打开了几个描述符的进程而言这点改进算不得什么,但对于那些打开了几千个文件描述符的程序来说,这种性能改进就相当显著了。这就是kqueue诞生背后的主要目的。同时,设计者还希望进程能够检测更多类型的事件,比如文件修改、文件删除、信号交付或者子进程退出,并提供一个包含了其它任务的灵活的函数调用。处理信号、复用文件描述符、以及等待子进程等操作都可以封装到这个单一的kqueue接口中,因为它们都是在等待某个事件的发生。

另一个设计考虑就是如何让一个进程毫无干扰地使用多个kqueue实例。如你所见,进程可以设置一个信号处理器,但是,当代码中的其它部分也想捕获那个指定信号的时候该怎么办?或者考虑更坏的情况,比如一个库函数对你的程序想要捕获的信号设置了信号处理器的时候?要想通过调试来找出你的程序为什么没有执行你所设置的信号处理器可能要花费几个小时的时间。不过一般说来,这些情况并不会经常发生。好的程序员应该避免在库函数中设置信号处理器。对于大型的、复杂的程序来说,这些情况就很难避免了,所以为了更完美一点,我们应当能够检测这些事件,而kqueue就可以。

kqueue API由两个函数调用和一个辅助设置事件的宏组成。这些函数将在下面进行简要介绍。

 
  int kqueue(void);
kqueue函数启动一个新的kqueue。如果调用成功,返回值将是一个用来和新创建的kqueue交互的描述符。每个kqueue都有一个与之关联的唯一的描述符。因此,一个程序可以同时打开多个kqueue。kqueue描述符的行为和常规文件描述符类似:它们也可以被复用。

最后一点,这些描述符是不能被fork创建的子进程继承的。如果子进程是通过rfork调用创建的,那就需要设置RFFDG标志,以免这些描述符被子进程共享。如果kqueue函数失败,将返回-1,同时相应的设置errno。

 
  int kevent(int kq, const struct kevent *changelist, int nchanges, struct kevent *eventlist, int nevents, const struct timespec *timeout);
kevent函数用于和kqueue的交互。第一个参数是kqueue返回的描述符。changelist参数是一个大小为nchanges的kevent结构体数组。changelist参数用于注册或修改事件,并且将在从kqueue读出事件之前得到处理。

eventlist参数是一个大小为nevents的kevent结构体数组。kevent通过把事件放在eventlist参数中来向调用进程返回事件。如果需要的话,eventlist和changelist参数可以指向同一个数组。最后一个参数是kevent所期待的超时时间。如果超时参数被指定为NULL,kevent将阻塞,直至有事件发生为止。如果超时参数不为NULL,则kevent将阻塞到超时为止。如果超时参数指定的是一个内容为0的结构体,kevent将立即返回所有当前尚未处理的事件。

kevent的返回值指定了放在eventlist数组中的事件的数目。如果事件数目超过了eventlist的大小,可以通过后续的kevent调用来获得它们。在处理事件的过程中发生的错误也会在还有空间的前提下被放到eventlist参数中。带有错误的事件会设置EV_ERROR位,系统错误也会被放到data成员中。对于其它的所有错误都将返回-1,并相应地设置errno。

kevent结构体用于和kqueue的通信。FreeBSD上的头文件位于/usr/include/sys/event.h。在这个文件中有对kevent结构体的声明,以及其它的一些选项和标志。和select和poll比起来,kqueue还相当的年轻,所以它一直都在发展和添加新的特性。请查看你的系统头文件以确定任何新的或者特定于系统的选项。

原始的kevent结构体的声明如下:

 
  struct kevent {
        uintptr_t       ident;
        short           filter;
        u_short         flags;
        u_int           fflags;
        intptr_t        data;
        void            *udata;
  };
现在,让我们来看看各个成员:

ident

ident成员用于存储kqueue的唯一标识。换句话说,如果你想给一个事件添加一个文件描述符的话,ident成员就应当被设置成目标描述符的值。

filter

filter成员用于指定你希望内核用于ident成员的过滤器。

flags

flags成员将告诉内核应当对该事件完成哪些操作和处理哪些必要的标志。在返回的时候,flags成员可用于保存错误条件。

fflags

fflags成员用于指定你想让内核使用的特定于过滤器的标志。在返回的时候,fflags成员可用于保存特定于过滤器的返回值。

data

data成员用于保存任何特定于过滤器的数据。

udata

udata成员并不由kqueue使用,kqueue会把它的值不加修改地透传。这个成员可被进程用来发送信息甚至是一个函数给它自己,用于一些依赖于事件检测的场合。

kqueue 过滤器

下面列出的是kqueue使用的过滤器。某些过滤器会有专用于它的标志。这些标志是在kevent结构体的fflags成员中设置的。

 
  #define EVFILT_READ     (-1)
EVFILT_READ过滤器用于检测什么时候数据可读。kevent的ident成员应当被设成一个有效的描述符。尽管这个过滤器的行为和select或这poll很像,但它返回的事件将是特定于所使用的描述符的类型的。

如果描述符引用的打开文件是一个vnode,该事件就表明读取偏移量尚未到达文件末尾。data成员保存的是当前距文件末尾的偏移量,这可以是负值。如果描述符引用的是一个pipe或者fifo,那么过滤器将在有实际数据可读时返回。data成员保存的是可供读取的字节数目。EV_EOF bit用于表示是哪个写入者关闭了连接。(关于使用socket时EVFILT_READ的行为细节请参见kqueue的手册页。)

 
  #define EVFILT_WRITE    (-2)
EVFILT_WRITE过滤器用于检测是否可以对描述符执行写操作。如果描述符引用的是一个pipe、fifo或者socket,则data成员将存有写缓冲区中可用的字节数目。EV_EOF bit表示读取方已经关闭了连接。这个标志对于打开的文件描述符无效。

 
  #define EVFILT_AIO      (-3)
EVFILT_AIO用于异步I/O操作,用于检测和aio_error系统调用相似的条件。

 
  #define EVFILT_VNODE    (-4)
EVFILT_VNODE过滤器用于检测对文件系统上一个文件的某种改动。把ident成员设置成一个有效的打开文件描述符,用fflags成员指定所关心的事件。返回时,fflags成员将含有所发生事件的比特掩码。这些事件如下:

 
  #define NOTE_DELETE     0x0001
NOTE_DELETE fflag表示进程想知道该文件何时被删。

 
  #define NOTE_WRITE      0x0002
NOTE_WRITE fflag表示进程想知道该文件内容何时被改变。

 
  #define NOTE_EXTEND     0x0004
NOTE_EXTEND fflag表示进程想知道该文件何时被扩展。

 
  #define NOTE_ATTRIB     0x0008
NOTE_ATTRIB fflag表示进程想知道该文件属性何时被改变。

 
  #define NOTE_LINK       0x0010
NOTE_LINK fflag表示进程想知道该文件的链接计数何时被改变。当文件通过link函数调用进行硬链接的时候,它的链接计数就会改变。(详情请参见man(2) link。)

 
  #define NOTE_RENAME     0x0020
NOTE_RENAME fflag表示进程想知道该文件是否被重新命名了。

 
  #define NOTE_REVOKE     0x0040
NOTE_REVOKE fflag表示对文件的访问被revoke了。详情请见man(2) revoke。

 
  #define EVFILT_PROC     (-5)  /* attached to struct proc */
EVLILT_PROC过滤器被进程用来检测发生在另外一个进程里的事件。所关心进程的PID存储在ident成员中,fflags成员则被设成所关心的事件。返回时,事件将被放在fflags成员中。这些事件由下列事件按比特OR的方式设置:

 
  #define NOTE_EXIT       0x80000000
NOTE_EXIT fflag用于检测该进程何时退出。

 
  #define NOTE_FORK       0x40000000
NOTE_FORK fflag用于检测该进程何时调用fork。

 
  #define NOTE_EXEC       0x20000000
NOTE_EXEC fflag用于检测该进程何时调用exec函数。

 
  #define NOTE_TRACK      0x00000001
NOTE_TRACK fflag让kqueue去跟踪一个跨越fork调用的进程。子进程返回时将设置fflags中的NOTE_CHILD标志,父进程的PID将放在data成员中。

 
  #define NOTE_TRACKERR   0x00000002
当在跟踪子进程的过程中有错误发生时,就会设置NOTE_TRACKERR fflag。这是一个仅用于返回的fflag。

 
  #define NOTE_CHILD      0x00000004
NOTE_CHILD fflag在子进程内设置。这是一个仅用于返回的fflag。

 
  #define EVFILT_SIGNAL      (-6)
EVFILT_SIGNAL过滤器用于检测是否有信号发送给该进程。每当有信号发送时这个过滤器就会检测到,并把计数值放在data成员中。这包括设置了SIG_IGN标志的信号。事件将在执行完常规的信号处理过程之后放到kqueue上。注意,这个过滤器将在内部设置EV_CLEAR标志。

 
  #define EVFILT_TIMER    (-7)
EVFILT_TIMER过滤器会给kqueue创建一个定时器,用于记录消逝的事件。如果需要一个一次性的定时器,可以设置EV_ONESHOT标志。这个定时器是在ident成员中指定的,data成员用来指定以毫秒为单位的超时时间。返回值放在data成员中。注意,这个过滤器将在内部设置EV_CLEAR标志。

kqueue操作

kqueue操作由所需的操作和标志以比特OR的方式进行设置。
 
  #define EV_ADD          0x0001
EV_ADD操作向kqueue添加事件。由于kqueue中不允许出现重复,所以如果你想添加一个已经存在的事件的话,现有事件将被新的添加操作覆盖。注意,在添加事件的时候,它们已经被默认激活了,除非你设置了EV_DISABLE标志。

 
  #define EV_DELETE       0x0002
EV_DELETE操作从kqueue中删除事件。

 
  #define EV_ENABLE       0x0004
EV_ENABLE用于激活kqueue中的事件。注意,新添加的事件默认就是激活的。

 
  #define EV_DISABLE      0x0008
EV_DISABLE禁止kqueue返回某个事件的信息。注意,kqueue并不会删除过滤器。

kqueue操作标志

kqueue的操作标志定义如下。它们和上面列出的操作结合使用。它们是通过和所需操作进行比特OR来设置的。

 
  #define EV_ONESHOT      0x0010
EV_ONESHOT标志用于通知kqueue只返回第一个。

 
  #define EV_CLEAR        0x0020
EV_CLEAR标志用于通知kqueue,一旦进程从kqueue中获取到了该事件就将该事件的状态复位。

kqueue返回值

仅用于返回的值是放在kevent结构体的flags成员中的。这些值的定义如下:

 
  #define EV_EOF          0x8000
EV_EOF用于表示文件结束的情况。

 
  #define EV_ERROR        0x4000
EV_ERROR用于表示有错误发生了。系统错误将被放到data成员中。

6.5 结论

本章研究了BSD中的描述符复用。作为一个程序员,你可以选择三个接口:select、poll和kqueue。对于小数量的描述符来说,这三者的性能差不多,但是当描述符数量很大时,kqueue则是最好的选择。除此之外,kqueue还可以检测比I/O事件更为丰富的条件。它可以检测信号、文件修改以及子进程相关的事件。在下一章中,我们将针对FreeBSD 5.x中的新特性,研究其它的获取子进程信息和当前进程统计信息的方法。
<script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script> <script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"> </script>pe="text/javascript">

 

 
C++高性能服务器优化:从阻塞模型到非阻塞I/O多路复用实战 在网络编程中,I/O多路复用是一种核心机制,它允许单个线程高效监控和管理大量网络连接的状态变化。其原理在于通过系统调用(如epoll、kqueue)将多个文件描述符的I/O事件集中处理,当任一描述符就绪时,内核通知应用程序进行非阻塞读写,从而避免了传统阻塞模型中为每个连接创建独立线程带来的巨大资源开销和上下文切换损耗。这项技术的核心价值在于显著提升服务器的并发处理能力和资源利用率,是实现高并发、高性能网络服务(如Web服务器、实时通信系统)的基石。在C++服务器开发中,结合非阻塞I/O与事件驱动架构,能够有 阅读详情

相关推荐

FreeBSD FEMP栈深度实践:ZFS、kqueue与系统协同调优

Web服务栈(LAMP/FEMP)本质上是操作系统与应用层的契约关系。在Linux生态中,抽象层掩盖了底层细节;而在FreeBSD上,Nginx的kqueue事件驱动、MySQL对ZFS写时复制与ARC缓存的依赖、PHP-FPM与rc.d服务框架的进程生命周期管理,共同构成一套可审计、可预测的系统级协同机制。这种确定性使FEMP特别适用于金融数据聚合、教育平台等对IO一致性、快照回滚和多租户隔离有严苛要求的场景。本文聚焦FreeBSD 10.1至15.1演进中不变的核心——ZFS recordsize与In

weixin_33716154的博客 332

FreeBSD Kqueue的实现原理

FreeBSD Kqueue的实现原理_mumumuwudi的博客-优快云博客

阳光梦的专栏 373

FreeBSD 11.2 下 Nginx 混合安装与生产级配置实战

Nginx 是高性能 Web 服务器与反向代理的工业标准,其核心能力依赖 OpenSSL、PCRE 等底层库的版本兼容性与模块化编译机制。在 FreeBSD 系统中,由于 ABI 稳定性约束和 pkg/ports 双生态设计,直接套用 Linux 安装流程极易导致 HTTPS 不可用、TLS 1.3 缺失、syslog 不合规等生产故障。本文聚焦 FreeBSD 11.2 这一典型遗留环境,解析如何通过 pkg 基础框架 + ports 精准编译的混合安装法,安全启用 http_ssl_module、HTT

weixin_34245749的博客 502

使用 kqueue 在 FreeBSD 上开发高性能应用服务器

概述 kqueue 是 FreeBSD 上的一种的多路复用机制。它是针对传统的 select/poll 处理大量的文件描述符性能较低效而开发出来的。注册一批描述符到 kqueue 以后,当其中的描述符状态发生变化时,kqueue 将一次性通知应用程序哪些描述符可读、可写或出错了。 kqueue 支持多种类型的文件描述符,包括 socket、信号、定时器、AIO、VNODE、PIPE。本

robertzhouxh的专栏 695

FreeBSD FAMP 部署实战:从 rc.d 服务注册到 kqueue+PHP-FPM 深度优化

FAMP(FreeBSD + Apache + MySQL + PHP)是面向高安全、强稳定场景的 Web 栈部署范式,其核心在于深度适配 FreeBSD 独有的系统机制。不同于 Linux 的 systemd/cgroup,FreeBSD 依赖 rc.d 服务注册、kqueue I/O 多路复用、rctl 资源控制与 Capsicum 能力沙箱等原生设施。Apache 的 event MPM 在 kqueue 支持下可承载超 8000 并发,而 PHP-FPM 通过 Unix socket 对接,实现进程

weixin_30797199的博客 309

从阻塞到非阻塞:C++ Web服务器性能提升6倍的架构演进

在网络编程中,I/O模型是决定服务器并发能力的关键技术。传统的阻塞I/O模型通过为每个连接创建独立线程来处理请求,虽然编程简单直观,但在高并发场景下会因线程资源消耗巨大和CPU闲置导致性能瓶颈。其核心原理是线程在等待I/O操作完成时会主动挂起,造成系统资源浪费。而非阻塞I/O与事件驱动模型则通过I/O多路复用技术(如epoll、kqueue)实现了根本性突破,允许单个线程同时监控大量连接,仅在I/O就绪时进行处理,从而将CPU时间集中于实际数据处理,大幅提升了吞吐量。这种架构的技术价值在于能够以极少的线程资

weixin_33743248的博客 452

KQUEUE FreeBSD

NAME kqueue, kevent -- kernel event notification mechanism LIBRARY Standard C Library (libc, -lc) SYNOPSIS #include sys/types.h> #include sys/event.h> #include sys/time.h>

WHACKW的专栏 1077

C++高性能网络编程终极指南:io_uring与kqueue核心机制与实战

I/O多路复用是构建高并发网络服务的核心技术,它允许单个线程高效监控和管理大量网络连接上的I/O事件。其核心原理在于操作系统提供统一的接口,将多个文件描述符(如socket)的I/O就绪状态通知给应用程序,从而避免了为每个连接创建线程或进程的巨大开销。这项技术的价值在于能够以极低的资源消耗支撑海量并发连接,是构建现代高性能服务器(如游戏服务器、金融交易系统、实时通信服务)的基石。其典型应用场景包括Web服务器、API网关、消息队列代理等需要处理成千上万同时连接的服务。本文聚焦于Linux的io_uring和

chaoyv 375

给Unity技能按钮加圆形CD效果:Unity3DTraining的SkillItem案例实操拆解

按下一个技能键之后,玩家最想知道的一件事是:还要等多久才能再放一次?很多新手的第一反应是把整个图标变灰,然后盯着它等,完全不知道还剩多少时间。Unity3DTraining 仓库的 UGUITraining/UGUIDemo02 案例里就有一套可以直接抄走的 Unity 技能冷却 / CD系统写法:按下技能键,图标上开始转圈,圈走完,技能恢复可用。下面带你把这套东西拆开看一遍。 ## 为什么CD

gitblog_00326的博客 449

pdfork:在FreeBSD上使用进程描述符(pdfork)的Rust fork包装器,在其他地方使用常规fork

pdfork Rust分支包装器,在FreeBSD上使用进程描述符(pdfork),在其他地方使用常规分支。 进程描述符类似于文件描述符,但用于进程: 它们不受PID竞争条件的影响(它们跟踪内核中的确切进程); 它们在功能模式沙箱中工作。 extern crate libc; extern crate pdfork; use pdfork :: * ; match fork () { ForkResult :: Fail => panic! ( "fork" ), ForkResult :: Parent (child_proc) => { // do stuff // you can access child_proc.child_pid on any platform // you can also access

手把手教你用C#实现TwinCAT 3 ADS通讯(附完整代码示例)

本文详细解析了如何使用C#实现TwinCAT 3 ADS通讯,包括协议核心价值、开发环境配置、变量通信实践及高级应用场景。通过完整代码示例和性能优化技巧,帮助开发者高效实现工业自动化系统中的实时数据交换,特别适合倍福(Beckhoff)平台用户。

weixin_29230901的博客 117

KQUEUE(2) FreeBSD System Calls Manual KQUEUE(2)

 NAME     kqueue, kevent -- kernel event notification mechanism 内核事件通知机制LIBRARY     Standard C Library (libc, -lc)SYNOPSIS     #include      #include      #include      int     kqueue(void);     i

walkingtour的专栏 895

当兵心理测试软件,当兵心理测试题及答案

心理测试是一种比较先进的测试方法,它是指通过一系列手段,将人的某些心理特征数量化,来衡量个体心理因素水平和个体心理差异差异的一种科学测量方法。小编为你整理了当兵心理测试题及答案,希望对你有所参考帮助。征兵心理测试题(1代表是2代表否)1、我的胃口很好。12、我早上起来的时候,多半觉得睡眠充足,头脑清醒13、我喜欢看报纸上的犯罪新闻。14、有时我常感到困难重重,无法克服。25、我时常遇见一些所谓的专...

weixin_42128393的博客 1万+

高级轮询技术——/dev/poll接口与kqueue

写在转载之前的: 在nginx源码src/event/ngx_event.h中涉及了好几种网络模型: windows select windows IOCP select poll epoll devpoll kqueue eventport 废弃的: glibc aio rtsig 可以说不同的系统,使用的方式不尽相同,是时候该对它们总结一下了。 以下是转载内容: 这里介绍两种机制,它们跟select和poll这两个函数具备类似的特性。 /dev/poll接口 Solaris上名为/dev/

格物致知的专栏 [音视频编解码 网络协议 计算机视觉 计算机图形学 图像理解 语音识别 机器学习 模拟电路 传感器] 705

深入探讨 VQ-VAE:理解变分量化自动编码器

VQ-VAE代表"Variational Quantized Variational Autoencoder",是一种生成模型,通常用于处理高维数据,如图像和音频。它的设计灵感来自于变分自动编码器(VAE)和量化方法,结合了它们的优点,使得 VQ-VAE 能够生成高质量的数据,并在数据表示上引入离散性。VQ-VAE 是一种强大的生成模型,结合了变分自动编码器和量化方法的优点。它在图像和音频生成、数据压缩和生成性对抗网络等领域具有广泛的应用。

DeepViewInsight的博客 7016

第10章:位同步与Gardner环路(1)

第10章(1)内容如下:一、位同步与载波同步的区别1、采样时钟相位偏差的影响2、采样时钟频率偏差的影响二、Gardner环路算法与插值方法1、插值滤波器2、Gardner误差检查算法三、Gardner环路中环路滤波器与数字振荡器设计1、环路滤波器2、数控振荡器(NCO)四、Gardner环路的可运行MATLAB代码五、参考资料六、致谢 最近搞懂了Gardner环路的一些知识,于是更新第10章——位同步。 如果你稍不留意的话,这可能是你在网上能看到的介绍Gardner环路及其MATLAB仿真最详细的一篇文章了

weixin_44283855的博客 1万+

[13]APUE:KQUEUE / FreeBSD

[a] 概述 kqueue API 由两个函数(kqueue、kevent)、一个辅助宏(EV_SET)、一个结构体(struct kevent)构成,可以应用于 socket、FIFO、pipe、aio、signal、process、regular file、path 等对象 与 Linux 下的 epoll 功能类似,性能相当 [b] kqueue / kevent / EV_S...

weixin_30386713的博客 173

注册“Oracle Provider for OLE DB”和创建链接服务器

注册“Oracle Provider for OLE DB”和创建链接服务器 在sql server 数据库上创建链接服务器,连接oracle数据库,访问接口需要设置为:“Oracle Provider for OLE DB”。 如果电脑上没有这个驱动,安装一个完整的Oracle11gR2程序是一个有效的方法,但这个64位版本的安装包有2个多G, 相当庞大,如果仅仅...

weixin_30760895的博客 2384

服务端处理常用的5种基础策略

一、一个线程服务多个客户端,使用非阻塞I/O和水平触发的就绪通知 把网络句柄设置为非阻塞模型,然后使用select()或poll()来告知哪个句柄已有数据在等待处理。此模型是最传统的,在此模型下,由内核告知你某个文件描述符是否准备好,是否已经完成你的任务自从上次内核告知已准备好以来(“水平触发”这个名字来源计算机硬件设计,与其相对的是“边缘触发”,JonathonLemon在它的关于kque

Working... 1432

affymatrix探针转换 | GPL5175探针对应的基因转换

一般情况下,有一些比较成熟的对应平台的注释数据集的R包。但是这个注释平台,我在Bioconductor上找了一圈都没有找到。只能通过最原始也最可靠的方法,从GEO数据集上去下载这部分的注释文件。以下展示全过程。 我要检查的数据平台是:GPL5157。 数据集的注释集链接为:https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc=GPL5175 这个注释数据集比较难弄的地方在于,它的基因集注释的不太好。没有比较直接的可供提取的genesample的信息;在ge.

weixin_40640700的博客 7124

【ARM Trace32(劳特巴赫) 高级篇 20 -- SNOOPer 使用介绍】

在 Lauterbach TRACE32 调试系统中,Snooper是一种特殊的监视工具,它能够在不中断处理器执行的情况下监视和记录特定内存地址的数据变化。这对于系统级调试、性能分析、数据流监视以及实时系统的问题追踪特别有用,尤其是在无法使用中断的情况下。当你设置了一个或多个Snooper时,TRACE32 硬件将不断地监视指定的内存地址,一旦发生了读写操作,就会将相关信息记录下来。这样你就可以看到某个地址的数据是什么时候以及如何被修改的,而不会影响目标系统的运行。

CodingCos的博客 2765

FreeBSD kqueue 这种多路复用 IO 模型的用法

<br />#include <iostream> <br />#include <string> <br />#include <sys/types.h> <br />#include <sys/socket.h> <br />#include <sys/event.h> <br />#include <sys/time.h> <br />#include <netinet/in.h> <br />#include <arpa/inet.h> <br />#include <errno.h> <br />

逆雪寒的天坑 1351

Uncaught ReferenceError: process is not defined

这个错误 Uncaught ReferenceError: process is not defined 通常出现在浏览器环境中,因为 process 是 Node.js 环境的内置对象,并不是浏览器原生支持的。因此,浏览器无法识别 process,导致该错误。在App.vue中加上以下代码就能够有效解决。

猿小白的博客 1740

C++非阻塞Web服务器实战:从9千到5.8万QPS的性能优化

在网络编程中,I/O多路复用是解决高并发连接的核心技术,它通过一个系统调用同时监控多个文件描述符的状态,从而让单个线程能够高效管理成千上万个连接。其原理在于将传统的阻塞式I/O模型升级为非阻塞模式,结合select、poll或更高效的epoll/kqueue等系统接口,实现事件驱动架构。这项技术的核心价值在于突破C10K问题,显著减少线程创建与上下文切换的开销,极大提升资源利用率。在应用场景上,它是构建现代高性能Web服务器、实时通信系统和微服务网关的基础。本文以C++ Web服务器为例,通过对比阻塞模型与

weixin_33924770的博客 965

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

上一篇: #define 的用法
下一篇: Siege:压力模拟/测试工具
linuxchen
博客等级 码龄24年 34粉丝 96原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值