本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。
本篇文章给大家谈谈事件通知模型,以及对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
今天给各位分享事件通知模型的知识,其中也会对进行解释,如果能碰巧解决你现在面临的问题,别忘了关注本站,现在开始吧!
本文目录一览:
Socket编程的几种模式
其基本原理是:首先建立一个socket连接,然后对其进行操作,比如,从该socket读数据。因为网络传输是要一定的时间的,即使网络通畅的情况下,接受数据的操作也要花费时间。对于一个简单的单线程程序,接收数据的过程是无法处理其他操作的。比如一个窗口程序,当你接收数据时,点击按钮或关闭窗口操作都不会有效。它的缺点显而易见,一个线程你只能处理一个 socket,用来教课还行,实际使用效果就不行了。select模型 为了处理多个socket连接,聪明的人们发明了select模型。该模型以集合来管理socket连接,每次去查询集合中的socket状态,从而达到处理多连接的能力,其函数原型是int select(int nfds, fd_set FAR * readfds, fd_set FAR * writefds, fd_set FAR * exceptfds, const struct timeval FAR * timeout)。比如我们判断某个socket是否有数据可读,我们首先将一个fdread集合置空,然后将socket加入到该集合,调用 select(0,fdread,NULL,NULL,NULL),之后我们判断socket是否还在fdread中,如果还在,则说明有数据可读。数据的读取和阻塞模型相同,调用recv函数。但是每个集合容量都有一个限值,默认情况下是64个,当然你可以重新定义它的大小,但还是有一个最上限,自己设置也不能超过该值,一般情况下是1024。尽管select模型可以处理多连接,但集合的管理多少让人感到繁琐。异步选择模型 熟悉windows操作系统的都知道,其窗口处理是基于消息的。人们又发明了一种新的网络模型——WSAAsyncSelect模型,即异步选择模型。该模型为每个socket绑定一个消息,当socket上出现事先设置的socket事件时,操作系统就会给应用程序发送这个消息,从而对该 socket事件进行处理,其函数原型是int WSAAsynSelect(SOCKET s, HWND hWnd, unsigned int wMsg, long lEvent)。hWnd指明接收消息的句柄,wMsg指定消息ID,lEvent按位设置感兴趣的网络事件,入 WSAAsyncSelect(s,hwnd,WM_SOCKET, FD_CONNECT | FD_READ | FD_CLOSE)。该模型的优点是在系统开销不大的情况下同时处理许多连接,也不需要什么集合管理。缺点很明显,即使你的程序不需要窗口,也要专门为 WSAAsyncSelect模型定义一个窗口。另外,让单个窗口去处理成千上万的socket操作事件,很可能成为性能瓶颈。事件选择模型 与WSAAsynSelect模型类似,人们还发明了WSAEventSelect模型,即事件选择模型。看名字就可以猜测出来,它是基于事件的。WSAAsynSelect模型在出现感兴趣的socket事件时,系统会发一个相应的消息。而WSAEventSelect模型在出现感兴趣的socket事件时,系统会将相应WSAEVENT事件设为传信。可能你现在对sokect事件和普通WSAEVENT事件还不是很清楚。 socket事件是与socket操作相关的一些事件,如FD_READ,FD_WRITE,FD_ACCEPT等。而WSAEVENT事件是传统的事件,该事件有两种状态,传信(signaled)和未传信(non-signaled)。所谓传信,就是事件发生了,未传信就是还没有发生。我们每次建立一个连接,都为其绑定一个事件,等到该连接变化时,事件就会变为传信状态。那么,谁去接受这个事件变化呢?我们通过一个 WSAWaitForMultipleEvents(...)函数来等待事件发生,传入参数中的事件数组中,只有有一个事件发生,该函数就会返回(也可以设置为所有事件发生才返回,在这里没用),返回值为事件的数组序号,这样我们就知道了哪个事件发生了,也就是该事件对应的socket有了socket操作事件。该模型比起WSAAsynSelect模型的优势很明显,不需要窗口。唯一缺点是,该模型每次只能等待64个事件,这一限制使得在处理多 socket时,有必要组织一个线程池,伸缩性不如后面要讲的重叠模型。重叠I/O(Overlapped I/O)模型重叠I/O(Overlapped I/O)模型使应用程序达到更佳的系统性能。重叠模型的基本设计原理是让应用程序使用重叠数据结构,一次投递一个或多个Winsock I/O请求。重叠模型到底是什么东西呢?可以与WSAEventSelect模型做类比(其实不恰当,后面再说),事件选择模型为每个socket连接绑定了一个事件,而重叠模型为每个socket连接绑定了一个重叠。当连接上发生socket事件时,对应的重叠就会被更新。其实重叠的高明之处在于,它在更新重叠的同时,还把网络数据传到了实现指定的缓存区中。我们知道,前面的网络模型都要用户自己通过recv函数来接受数据,这样就降低了效率。我们打个比方,WSAEventSelect模型就像邮局的包裹通知,用户收到通知后要自己去邮局取包裹。而重叠模型就像送货上门,邮递员发给你通知时,也把包裹放到了你事先指定的仓库中。
重叠模型又分为事件通知和完成例程两种模式。在分析这两种模式之前,我们还是来看看重叠数据结构:
typedef struct WSAOVERLAPPED{DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
WSAEVENT hEvent;
}WSAOVERLAPPED, FAR * LPWSAOVERLAPPED;
该数据结构中,Internal、InternalHigh、Offset、OffsetHigh都是系统使用的,用户不用去管,唯一关注的就是 hEvent。如果使用事件通知模式,那么hEvent就指向相应的事件句柄。如果是完成例程模式,hEvent设为NULL。我们现在来看事件通知模式,首先创建一个事件hEvent,并创建一个重叠结构AcceptOverlapped,并设置AcceptOverlapped.hEvent = hEvent,DataBuf是我们事先设置的数据缓存区。调用 WSARecv(AcceptSocket,DataBuf,1,RecvBytes,Flags,AcceptOverlapped,NULL),则将AcceptSocket与AcceptOverlapped重叠绑定在了一起。当接收到数据以后,hEvent就会设为传信,而数据就会放到 DataBuf中。我们再通过WSAWaitForMultipleEvents(...)接收到该事件通知。这里我们要注意,既然是基于事件通知的,那它就有一个事件处理上限,一般为64。
完成例程和事件通知模式的区别在于,当相应的socket事件出现时,系统会调用用户事先指定的回调函数,而不是设置事件。其实就是将WSARecv的最后一个参数设为函数指针。该回调函数的原型如下:
void CALLBACK CompletionROUTINE(
DWORD dwError,
DWORD cbTransferred,
LPWSAOVERLAPPED lpOverlapped,
DWORD dwFlags);其中,cbTransferred表示传输的字节数,lpOverlapped是发生socket事件的重叠指针。我们调用 WSARecv(AcceptSocket,DataBuf,1,RecvBytes,Flags,AcceptOverlapped,WorkerRoutine) 将AcceptSocket与WorkRoutine例程绑定。这里有一点小提示,当我们创建多个socket的连接时,最好把重叠与相应的数据缓存区用一个大的数据结构放到一块,这样,我们在例程中通过lpOverlapped指针就可以直接找到相应的数据缓存区。这里要注意,不能将多个重叠使用同一个数据缓存区,这样在多个重叠都在处理时,就会出现数据混乱。完成端口模型 下面我们来介绍专门用于处理为数众多socket连接的网络模型——完成端口。因为需要做出大量的工作以便将socket添加到一个完成端口,而其他方法的初始化步骤则省事多了,所以对新手来说,完成端口模型好像过于复杂了。然而,一旦弄明白是怎么回事,就会发现步骤其实并非那么复杂。所谓完成端口,实际是Windows采用的一种I/O构造机制,除套接字句柄之外,还可以接受其他东西。使用这种模式之前,首先要创建一个I/O完成端口对象,该函数定义如下:
HANDLE CreateIoCompletionPort(
HANDLE FileHandle,
HANDLE ExistingCompletionPort,
DWORD CompletionKey,
DWORD NumberOfConcurrentThreads);该函数用于两个截然不同的目的:1)用于创建一个完成端口对象。2)将一个句柄同完成端口关联到一起。
通过参数NumberOfConcurrentThreads,我们可以指定同时运行的线程数。理想状态下,我们希望每个处理器各自负责一个线程的运行,为完成端口提供服务,避免过于频繁的线程任务切换。对于一个socket连接,我们通过 CreateIoCompletionPort((HANDLE)Accept,CompletionPort, (DWORD)PerHandleData,0)将Accept连接与CompletionPort完成端口绑定到一起,CompetionPort对应的那些线程不断通过GetQueuedCompletionStatus来查询与其关联的socket连接是否有I/O操作完成,如果有,则做相应的数据处理,然后通过WSARecv将该socket连接再次投递,继续工作。完成端口在性能和伸缩性方面表现都很好,相关联的socket连接数目没有限制。
汇总js事件相关及事件处理模型
js事件是为了实现用户交互,比如当用户鼠标点击或者键盘输入时,浏览器会监听截获并且通知js做出反馈执行相应的函数,实现交互。
js的事件类型有很多,我们先来大概总结一下常用的JS事件
click点击事件、mousedown鼠标按下事件、mousemove鼠标移动事件、mouseup鼠标抬起事件
contextmenu右键出菜单事件、mouseenter/mouseover鼠标进入事件、mouserleave/mouseout鼠标离开事件
可通过事件对象的button属性来区分是左键\滚轮\右键,分别对应值 0 / 1 / 2
DOM3规定:click事件只能监听左键;只能通过mousedown和mouseup来判断鼠标键
keydown某键被按下时、keyup被松开时、keypress按下并且松开时
触发顺序:先 keydown,然后keypress,最后keyup
keydown和keypress的区别:
input:文本变化时触发
change:聚焦或失去焦点时判断状态是否改变,发生改变是触发change事件
focus:聚焦时触发
blur:失去焦点时触发
利用focus和blur可模拟placeholder
scroll:滚动条滚动时
load:页面加载完触发
abort:图像的加载失败
dblclick:双击事件
error:当加载图像和文档时发生错误
resize:窗口或者框架被重新调整大小
select:文本被选中时
reset:点击重置按钮时
submit:点击提交按钮时
接着看如何给DOM元素绑定事件处理函数
兼容性很好
但是根据js的特点,这种赋值的方式肯定会被后面的值覆盖。因此这种方式绑定事件处理函数规则是:同一个元素同一个事件只能绑定一个处理函数。等同于第一种写在行间。
IE8及以下不兼容
通过addEventListener绑定的方式,同个元素的同一个事件可以绑定多个处理函数,不会被覆盖。
attachEvent跟addEventListener 基本一致,也是同一个元素的同一个事件可以绑定多个处理函数,不会被覆盖。不同的是attachEvent可以绑定的函数是可以重复的,即即使绑定同一个函数都不会不覆盖。
以上几种事件绑定方式里面的this指向有点区别:
也比较好理解,IE独有的特殊一点指向window,其他都指向dom元素本身
封装一个兼容性的方法,用于绑定事件:
有的时候我们希望解除事件处理函数,那怎么办呢?
其实解除事件处理函数也对应有办法方法:
1. ele.onxxx = false / ' ' / null
2. ele.removeEventListener(type,fnName,false)
3. ele.attachEvent('on' + type,fnName)
值得注意的是:若干绑定的事件处理函数是匿名函数,则无法解除绑定!
不知道有没有发现,在上面绑定事件处理函数的时候,处理函数有个参数e或者叫event,其实是一个事件对象
事件对象就是处理函数里面的一个参数,说白了就是浏览器打包好的一个对象自动传入到处理函数的第一个参数中。
为了兼容IE一般这么写: e = e || window.event
事件对象会有个属性target,这个target叫事件源对象,记录可事件具体在谁身上触发的那个源头
同样IE上事件源对象是e.srcElement,谷歌两个都有
所以为了兼容IE一般获取事件源对象是这么来写:
当浏览器发展到第四代时(IE4及Netscape4),浏览器开发团队遇到了一个很有意思的问题:页面的哪一部分会拥有某个特定的事件?想象画在一张纸上的一组同心圆。如果把手指放在圆心上,那么手指指向的不是一个圆,而是纸上的所有圆
两家公司的浏览器开发团队在看待浏览器事件方面还是一致的。如果单击了某个按钮,他们都认为单击事件不仅仅发生在按钮上,甚至也单击了整个页面
但有意思的是,IE和Netscape开发团队居然提出了差不多是完全相反的事件流的概念。IE的事件流是事件冒泡流,而Netscape的事件流是事件捕获流。事件冒泡和事件捕获称为两种事件处理模型
IE的事件流叫做事件冒泡(event bubbling), 事件冒泡是结构上(非视觉上)嵌套的函数存在事件冒泡功能,即同一事件自子元素冒泡向父元素(自底向上)
[注意]所有现代浏览器都支持事件冒泡
但在具体实现在还是有一些差别。IE9、Firefox、Chrome、Safari将事件一直冒泡到window对象
而事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预定目标之前就捕获它
即事件捕获是指: 结构上(非视觉上)嵌套的元素存在事件捕获功能,即同一事件自父元素冒泡向子元素(自顶向下)
注意IE上没有事件捕获,Chrome和新版本的Firefox等都实现了
一个dom元素的一个事件类型绑定的一个处理函数只能存在一种事件模型,要么事件冒泡要么事件捕获。正常的通过addEventListener(type,fn,false)绑定事件时,最后一个参数默认是false表示的是,事件冒泡模型。如果改成true,立即变成事件捕获模型
如果一个dom元素的一个事件类型绑定了两个处理函数,两个函数的事件处理模型一个是事件冒泡一个是事件捕获,触发顺序是先捕获,后冒泡。
focus、blur、change、submit、reset、select等事件类型不冒泡
可以 利用事件冒泡和事件源对象可以叫事件委托给父元素
利用事件冒泡和事件源对象进行处理
优点:
性能好,不需要循环所有元素一个个绑定事件
灵活,当有其他新的子元素时,不需要重新绑定事件。
有的时候,我们不希望有冒泡功能,那我们怎么取消事件冒泡呢?
封装一个都好使的取消冒泡函数
有的时候我们需要阻止一些浏览器默认的事件
比如:表单提交、a链接跳转、右键菜单等
有几种方式:
参考资料:
DOM事件流的三个阶段
深入理解DOM事件机制系列第一篇——事件流
JS事件汇总
JS事件模型
事件1(上)
事件1(下)
DOM级别与DOM事件
DOM事件机制解惑
事件模型
JavaScript 事件委托详解
JavaScript 事件的学与记:stopPropagation 和 stopImmediatePropagation
event.target和event.currentTarget的区别
js怎么区分出点击的是鼠标左键还是右键?
急!COM+Event Syetem(支持系统事件通知服务)能禁止开机启动吗?
COM+
Event
System
支持系统事件通知服务(SENS),此服务为订阅组件对象模型(COM)组件事件提供自动分布功能。如果停止此服务,SENS
将关闭,而且不能提供登录和注销通知。如果禁用此服务,显式依赖此服务的其他服务将无法启动。一个很原始的古老服务,该服务的默认运行方式为自动,这是一个重要的系统服务,设为手动也会自动运行,设为禁用好像也没什么影响,但是日志中会出现大量的错误。
我们最好不要乱动
。
\\WINDOWS\system32\svchost.exe
-k
netsvcs
事件驱动模型的epoll
epoll是和上面的poll和select不同的一个事件驱动库,它是在linux 2.5.44中引入的,它属于poll的一个变种。上面的poll和select库,它们的最大的问题就在于效率。它们的处理方式都是创建一个事件列表,然后把这个列表发给内核,返回的时候,再去轮询检查这个列表,这样在描述符比较多的应用中,效率就显得比较低下了。一种比较好的做法是,把描述符列表交给内核,一旦有事件发生,内核把发生事件的描述符列表通知给进程,这样就避免了轮询整个描述符列表。epoll就是这样一种模型。下面对epoll的使用进行说明:
(1).创建一个epoll描述符,调用epoll_create()来完成,epoll_create()有一个整型的参数size,用来告诉内核,要创建一个有size个描述符的事件列表(集合)
int epoll_create(int size)
(2).给描述符设置所关注的事件,并把它添加到内核的事件列表中去,这里需要调用epoll_ctl()来完成。
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
这里op参数有三种,分别代表三种操作:
a. EPOLL_CTL_ADD, 把要关注的描述符和对其关注的事件的结构,添加到内核的事件列表中去
b. EPOLL_CTL_DEL,把先前添加的描述符和对其关注的事件的结构,从内核的事件列表中去除
c. EPOLL_CTL_MOD,修改先前添加到内核的事件列表中的描述符的关注的事件
(3). 等待内核通知事件发生,得到发生事件的描述符的结构列表,该过程由epoll_wait()完成。得到事件列表后,就可以进行事件处理了。
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout)
在使用epoll的时候,有一个需要特别注意的地方,那就是epoll触发事件的文件有两种方式:
(1)Edge Triggered(ET),在这种情况下,事件是由数据到达边界触发的。所以要在处理读、写的时候,要不断的调用read/write,直到它们返回EAGAIN,然后再去epoll_wait(),等待下次事件的发生。这种方式适用要遵从下面的原则:
a. 使用非阻塞的I/O;b.直到read/write返回EAGAIN时,才去等待下一次事件的发生。
(2)Level Triggered(LT), 在这种情况下,epoll和poll类似,但处理速度上可能比poll快。在这种情况下,只要有数据没有读、写完,调用epoll_wait()的时候,就会有事件被触发。
关于事件通知模型和的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。
事件通知模型的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于、事件通知模型的信息别忘了在本站进行查找喔。
暂时没有评论,来抢沙发吧~