YY31代码31

当前位置:&>&
yy直播出事31分钟17秒视频完整版 女主角全程露脸
&  谁们家女主播这么不要脸 也不嫌丢人。为了炒作也真没谁了。全程看着摄像头明显这是故意的炒作。 为了钱真是什么都敢做。给直播这个行业抹黑。
我此时此刻只想对那男的说 。拿几个痔疮走吧,小流氓。
  真是奇葩了,yy女主播在视频底下啪啪啪;这女主播估计要被永久封了。以下是来自新浪微博的秒怕视频,还可以自己看下面的图片吧!
  31分钟的不雅视频尺度甚大,令人震惊。不过,网友表示,虽然这是全裸啪啪啪的视频,但看了几分钟就吐了。男人都爱看AV,为何会吐呢?原因有两个,第一,该女主播下面竟然长痔疮,啪啪啪时痔疮还出血了,十分恶心。第二,男子内射,白色的东西,看起来很恶心。
  从照片看,女主播长得肉肉的,身材不算性感,但挺丰满的。样貌嘛,还过得去。总体上呢,也称得上是一个美女。不过,男子就很普通,长得肥,而且丁丁很短。
  现在网上都称,这段不雅视频曝光,是因为女主播直播节目之后,忘记关视频了。后来跟男子全裸啪啪啪,所以被录像了。其实,小编觉得,女主播明显是摆拍,不是忘关视频,而是故意拍摄的。
  从视频看到,女主播一直盯着摄像头看,面无表情实在没意思!即使啪啪啪的时候,头部也是盯着摄像头,显然是知道在拍摄的。
  YY自从诞生之后成为很多宅男的娱乐方式,yy里面很多女主播多才多艺,赢得了大量粉丝,而且据媒体爆料,女主播的收入相当惊人,甚至有月收入过百万的,当然前提是有大量的粉丝。
  而一些女主播为吸引粉丝,就采取一些低俗的手段吸引流量和粉丝,而女主播忘记关闭摄像头的也大有人在。yy女主播经常爆出不雅视频或者艳照绯闻。
  不过也有网友认为这可能又是一起低俗的炒作,他表示听说yy出事了,传了一段视频,我去看了一下,是假的,视频很早之前就有了,600M完整版31分钟,流传的只是截取的。
猜你可能会喜欢的QQ资讯:
泡友留言() 请文明发表评论,恶意辱骂/诽谤,发布广告者封号处理!
热点推荐:当前位置:&>&
yy女主播直播啪啪啪全过程31分钟完整版视频在线观看
  据了解,YY女主播经常爆出不雅视频或者艳照绯闻。一些女主播为吸引粉丝,会采取一些低俗的手段吸引流量和粉丝。至于本次yy直播出事了视频是有意为之,还是真正忘记关摄像头,目前不得而知。  近日,微博热搜榜突然出现yy直播出事了等消息,打开之后原来是一名yy女主播在直播时忘记关闭摄像头,在和男友啪啪啪的时候正好出现在摄像头面前,两人的所作所为就这样被传到了网络之上。   视频中,女主播和一名男子两人全身赤裸啪啪啪,画面不堪入目,乳房和下体全裸露,连男子的丁丁也曝光,真心是一场”现场直播啊“这么不雅的视频是无意流出的还是故意的呢?  从照片看,女主播在与男友激情爱爱时还看着摄像头,如果是忘记关摄像头的话,怎么会一直看着呢?(真心敬业啊)而且给人的感觉也显的相当的刻意。不过如今视频大多都已经被和谐了,剩下的一小部分还网友们的硬盘还有网盘中呆着,也有一部分网友借此卖钱,对于这类网友小编只想说,呵呵。  8月7日晚,“yy直播出事”的视频已经在网上传开了,视频的总长度有31分钟,590.5M,有不少网友已经上传到百度云网盘上面保存了下来,但是看了视频的网友都觉得是炒作,因为网友们都发现女的根本就是整天看着镜头,也没有什么表情,应该是故意不关的。现在为了炒作也是什么事情都做的出来啊。  yy直播出事视频百度云网盘里面的资源,如果当晚没有下载下来的话,基本上已经被和谐了。  晚睡的孩子运气都不会太差啦,近期有网友调侃“刷微博就像逛窑子一样”,就在优衣库和HTC不雅视频先后曝光之后,YY直播平台的一名女主播今天凌晨再度成为刷屏人物。而且跟优衣库HTC不同的是,这个时长还相当给力,31分钟。  网络知名的yy女主播出事了,在和男友做爱的时候竟然忘关摄像头,全程直播啪啪啪全程,并且网友下载了31分钟无码版,在网上引起疯传,而男主角也惨遭网友吐槽丁丁很短。  yy女主播在视频底下啪啪啪,不过小编估计这女主播要被永久封了。31分钟的不雅视频尺度甚大,令人震惊。不过,网友表示,虽然这是全裸啪啪啪的视频,但看了几分钟就吐了。男人都爱看AV,为何会吐呢?   原因有两个,第一,该女主播下面竟然长痔疮,啪啪啪时痔疮还出血了,十分恶心(小编只想默默的问一句,那男的啪是时候不嫌恶心吗?)。第二,男子内射,白色的东西,看起来很恶心。第三:那男的JJ太小了,看起来不够带劲(丁丁:怪我咯?)。  在YY女主播直播出事的标题席卷网络后,很多晚起错过的网友,都纷纷到处求链接,但是在“yy直播啪啪啪”视频出现不久之后,就已经被和谐了,不仅仅是在微博,还有网络,甚至百度云都被和谐,现在如今网络上所谓的链接,大部分都是假的,希望网友们在点击的时候要慎重,以免视频没看到,还惹了一电脑的木马,且根据来自网友们的表述,视频看起来并不是那么的“神清气爽”,相反还有点恶心。
猜你可能会喜欢的QQ资讯:
泡友留言() 请文明发表评论,恶意辱骂/诽谤,发布广告者封号处理!
热点推荐:&这两天没事,看了一下Memcached和libevent的源码,做个小总结。
1.1、概述Libevent是一个用于开发可扩展性网络服务器的基于事件驱动(event-driven)模型的网络库。Libevent有几个显著的亮点: (1)事件驱动(event-driven),高性能;(2)轻量级,专注于网络,不如 ACE 那么臃肿庞大; (3)源代码相当精炼、易读; (4)跨平台,支持 Windows、Linux、*BSD和 Mac Os; (5)支持多种 I/O多路复用技术, epoll、poll、dev/poll、select 和kqueue 等; (6)支持 I/O,定时器和信号等事件; (7)注册事件优先级; &Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、 Vomi t、 Nylon、 Netchat等等。
1.2、一个简单示例
&1&int&&2&&3&static&void&4&timeout_cb(int&fd,&short&event,&void&*arg)&5&{&6&struct&timeval&&7&struct&event&*timeout&=&&8&int&newtime&=&time(NULL);&9&10&//printf("%s:&called&at&%d:&%d\n",&__func__,&newtime,11&printf("%s:&called&at&%d:&%d\n",&"timeout_cb",&newtime,12&&&&&&&&&newtime&-&lasttime);13&lasttime&=&14&15&evutil_timerclear(&tv);16&tv.tv_sec&=&2;17&//重新注册event18&event_add(timeout,&&tv);19&}20&21&int22&main&(int&argc,&char&**argv)23&{24&struct&event&25&struct&timeval&26&&27&/*&Initalize&the&event&library&*/28&//初始化event环境29&event_init();30&31&/*&Initalize&one&event&*/32&//设置事件33&evtimer_set(&timeout,&timeout_cb,&&timeout);34&35&evutil_timerclear(&tv);36&tv.tv_sec&=&2;37&//注册事件38&event_add(&timeout,&&tv);39&40&lasttime&=&time(NULL);41&&&&&42&//等待,分发,处理事件43&event_dispatch();44&45&return&(0);46&}
这是一个简单的基于libevent的定时器程序,运行结果:
用libevent编程非常简单,只需要调用event_init初始化环境,然后调用event_add注册相应的事件,接着调用event_dispatch等待并处理相应的事件即可。调用event_add注册事件时,设置其回调函数。Libevent检测到事件发生时,便会调用事件对应的回调用函数,执行相关的业务逻辑。1.3、源代码结构Libevent 的源代码虽然都在一层文件夹下面,但是其代码分类还是相当清晰的,主要可分为头文件、内部使用的头文件、辅助功能函数、日志、libevent 框架、对系统 I/O 多路复用机制的封装、信号管理、定时事件管理、缓冲区管理、基本数据结构和基于 libevent的两个实用库等几个部分,有些部分可能就是一个源文件。 (1)头文件 主要就是 event.h:事件宏定义、接口函数声明,主要结构体 event 的声明; (2)内部头文件 xxx-internal.h:内部数据结构和函数,对外不可见,以达到信息隐藏的目的; (3)libevent框架 event.c:event 整体框架的代码实现; (4)对系统 I/O多路复用机制的封装 epoll.c:对 epoll 的封装; select.c:对 select 的封装; devpoll.c:对 dev/poll 的封装; kqueue.c:对kqueue 的封装; (5)定时事件管理 min-heap.h:其实就是一个以时间作为 key的小根堆结构; (6)信号管理 signal.c:对信号事件的处理; (7)辅助功能函数 evutil.h& 和 evutil.c:一些辅助功能函数,包括创建 socket pair和一些时间操作函数:加、减和比较等。 (8)日志 log.h和 log.c:log 日志函数 (9)缓冲区管理 evbuffer.c 和buffer.c:libevent 对缓冲区的封装; (10)基本数据结构 compat\sys 下的两个源文件: queue.h是 libevent 基本数据结构的实现,包括链表,双向链表,队列等;_libevent_time.h:一些用于时间操作的结构体定义、函数和宏定义; (11)实用网络库 &&& &http 和evdns:是基于 libevent 实现的http 服务器和异步 dns 查询库;2、核心对象结构体event和event_base是libevent的两个核心数据结构,前者代表一个事件对象,后者代表整个事件处理框架。 2.1、event(事件)
&1&//event.h&2&struct&event&{&3&TAILQ_ENTRY&(event)&ev_&&&&&&&&&&//已注册事件链表&4&TAILQ_ENTRY&(event)&ev_active_//就绪事件链表&5&TAILQ_ENTRY&(event)&ev_signal_&//signal链表&6&unsigned&int&min_heap_&&&&/*&for&managing&timeouts,事件在堆中的下标&*/&7&&8&struct&event_base&*ev_&9&10&int&ev_&&&&&&//对于I/O事件,是绑定的文件描述符;对于signal事件,是绑定的信号11&short&ev_&//event关注的事件类型12&short&ev_&//事件就绪执行时,调用&ev_callback&的次数13&short&*ev_&&&&/*&Allows&deletes&in&callback&*/14&15&struct&timeval&ev_&&//timout事件的超时值16&17&int&ev_&&&/*&smaller&numbers&are&higher&priority,优先级&*/18&19&void&(*ev_callback)(int,&short,&void&*arg);&//回调函数20&void&*ev_&//回调函数的参数21&22&int&ev_&&&&&&&&/*&result&passed&to&event&callback&*/23&int&ev_&//event的状态24&};25&
Libevent通过event对象将I/O事件、信号事件和定时器事件封装,从而统一处理,这也是libevent的精妙所有。各个字段的具体含义:(1) ev_events:event关注的事件类型,它可以是以下3种类型: I/O事件: EV_WRITE和EV_READ 定时事件:EV_TIMEOUT 信号:&&& EV_SIGNAL 辅助选项:EV_PERSIST,表明是一个永久事件 libevent中的定义为:#define EV_TIMEOUT&& &0x01#define EV_READ&& &0x02#define EV_WRITE&& &0x04#define EV_SIGNAL&& &0x08#define EV_PERSIST&& &0x10&& &/* Persistant event */(2)ev_next,ev_active_next 和 ev_signal_next 都是双向链表节点指针;它们是 libevent 对不同事件类型和在不同的时期,对事件的管理时使用到的字段。 libevent 使用双向链表保存所有注册的 I/O和 Signal 事件,ev_next 就是该I/O事件在链表中的位置;此链表可以称为&已注册事件链表&; 同样 ev_signal_next 就是 signal 事件在 signal 事件链表中的位置; ev_active_next:libevent 将所有的激活事件放入到链表 active list 中,然后遍历 active list 执行调度,ev_active_next就指明了 event 在active list 中的位置;(3)min_heap_idx 和 ev_timeout,如果是 timeout 事件,它们是 event 在小根堆中的索引和超时值,libevent 使用小根堆来管理定时事件。(4)ev_base指向事件框架实例。(5)ev_fd,对于 I/O事件,是绑定的文件描述符;对于 signal 事件,是事件对应的信号;(6)eb_flags:libevent 用于标记 event信息的字段,表明事件当前的状态,可能的值有:#define EVLIST_TIMEOUT&& 0x01 // event在time堆中 #define EVLIST_INSERTED 0x02 // event在已注册事件链表中 #define EVLIST_SIGNAL&&& 0x04 // 未见使用 #define EVLIST_ACTIVE&&& 0x08 // event在激活链表中 #define EVLIST_INTERNAL 0x10 // 内部使用标记 #define EVLIST_INIT&&&&& 0x80 // event 已被初始化2.2、event_base(事件处理框架)
&1&//evenet_internal.h&2&struct&event_base&{&3&const&struct&eventop&*&//底层具体I/O&demultiplex操作函数集&4&void&*&5&int&event_&&&&&&&&/*&counts&number&of&total&events,总的事件数量&*/&6&int&event_count_&&&&/*&counts&number&of&active&events,就绪事件数量&*/&7&&8&int&event_&&&&&&&&/*&Set&to&terminate&loop&*/&9&int&event_&&&&&&&&/*&Set&to&terminate&loop&immediately&*/10&11&/*&active&event&management&*/12&//就绪事件链表数组13&struct&event_list&**14&int&//就绪事件队列个数15&16&/*&signal&handling&info&*/17&struct&evsignal_info&&//用于管理信号18&19&struct&event_list&&//注册事件队列20&struct&timeval&event_21&22&struct&min_heap&&//管理定时器的小根堆23&struct&timeval&tv_&//记录时间缓存24&};
(1)evsel:libevent支持Linux、Windows等多种平台,也支持epoll、poll、select、kqueue等多种I/O多路复用模型。如果把event_init、event_add看成高层抽象的统一事件操作接口,则evsel为这些函数在底层具体的I/O demultiplex的对应的操作函数集。eventop为函数指针的集合:
&1&struct&eventop&{&2&const&char&*&3&void&*(*init)(struct&event_base&*);&4&int&(*add)(void&*,&struct&event&*);&5&int&(*del)(void&*,&struct&event&*);&6&int&(*dispatch)(struct&event_base&*,&void&*,&struct&timeval&*);&7&void&(*dealloc)(struct&event_base&*,&void&*);&8&/*&set&if&we&need&to&reinitialize&the&event&base&*/&9&int&need_10&};11&
在初始化函数event_base_new中,libevent将evsel指向全局数组eventops的具体元素:
&1&//I/O&multiplex机制实例数组&2&static&const&struct&eventop&*eventops[]&=&{&3&#ifdef&HAVE_EVENT_PORTS&4&&evportops,&5&#endif&6&#ifdef&HAVE_WORKING_KQUEUE&7&&kqops,&8&#endif&9&#ifdef&HAVE_EPOLL10&&epollops,11&#endif12&#ifdef&HAVE_DEVPOLL13&&devpollops,14&#endif15&#ifdef&HAVE_POLL16&&pollops,17&#endif18&#ifdef&HAVE_SELECT19&&selectops,20&#endif21&#ifdef&WIN3222&&win32ops,23&#endif24&NULL25&};26&
2.3、主要函数2.3.1、event_int(初始化libevent实例)struct event_base *event_init(void)初始化事件处理框架实例,内部调用event_base_new。event_base_new的主要逻辑:
&1&struct&event_base&*&2&event_base_new(void)&3&{&4&&5&//初始化小根堆&6&min_heap_ctor(&base-&timeheap);&7&&8&//初始化注册事件队列&9&TAILQ_INIT(&base-&eventqueue);10&11&for&(i&=&0;&eventops[i]&&&&!base-&&i++)&{12&//I/O&demultiplex机制实例13&base-&evsel&=&eventops[i];14&15&//初始化I/O&demultiplex实例(参见win32_init)16&base-&evbase&=&base-&evsel-&init(base);17&}18&19&//分配1个就绪事件队列20&event_base_priority_init(base,&1);21&22&}
2.3.2、event_add(注册事件)//注册事件intevent_add(struct event *ev, const struct timeval *tv)该函数主要将事件ev加入到事件框架event_base的注册事件链表base-&eventqueue。2.3.3、event_del(删除事件)//删除事件intevent_del(struct event *ev)该函数主要将事件ev从相应的链表上删除。2.3.4、event_set(设置事件)
/*设置event对象**ev:事件对象**fd:事件对应的文件描述符或信号,对于定时器设为-1**events:事件类型,比如&EV_READ,EV_PERSIST,&EV_WRITE,&EV_SIGNAL**callback:事件的回调函数**arg:回调函数参数*/voidevent_set(struct&event&*ev,&int&fd,&short&events,&&&&&&void&(*callback)(int,&short,&void&*),&void&*arg)
在将事件注册事件处理框架之前,应该先调用event_set对事件进行相关设置。
2.4、libevent对event的管理event结构有3个链表结点域和一个小根堆索引,libevent通过3个链表和一个小根堆对I/O事件、signal事件和timer事件进行管理。对于I/O事件,通过event_add将其加入event_base的注册事件链表eventqueue ;就绪时会加入event_base的就绪链表activequeues[];对于timer事件,event_add将其加入到event_base的小根堆timeheap;Signale事件的管理相对复杂些,event_add将其加入到注册事件链表,同时,event_add内部会调用I/O demultiplex的add函数(对于I/O事件也一样),比如epoll_add。而add函数又会调用evsignal_add将其加入到evsignal_info的evsigevents[signo]链表(关于signal,后面会详细介绍)。
3、事件处理框架主循环Libevent将I/O事件、signal事件和timer事件用统一的模型进行处理,这是非常精妙的。libevent主循环函数不断检测注册事件,如果有事件发生,则将其放入就绪链表,并调用事件的回调函数,完成业务逻辑处理。3.1、event_dispatch//事件处理主循环intevent_dispatch(void)这是呈现给外部的接口,它的实现很简单,即调用event_loop,而event_loop调用event_base_loop,event_base_loop完成实际的主循环逻辑。3.2、event_base_loop主要算法:
&1&done&=&0;&2&while&(!done)&{&3&&4&/*如果没有就绪事件,根据timer&heap中事件的最小超时时间,计算I/O&demultiplex的&5&**最大等待时间.&相反,如果有就绪事件,则清除tv,即I/O&demultiplex不应该等待.&6&*/&7&if&(!base-&event_count_active&&&&!(flags&&&EVLOOP_NONBLOCK))&{&8&&&&&timeout_next(base,&&tv_p);&9&}&else&{10&&&&&/*&11&&&&&&*&if&we&have&active&events,&we&just&poll&new&events12&&&&&&*&without&waiting.13&&&&&&*/14&&&&&evutil_timerclear(&tv);15&}16&17&/*&If&we&have&no&events,&we&just&exit&*/18&//没有事件处理,则退出循环19&if&(!event_haveevents(base))&{20&&&&&event_debug(("%s:&no&events&registered.",&__func__));21&&&&&return&(1);22&}23&24&//tv_p为I/O&demultiplex的超时时间25&//处理signal事件和I/O事件26&res&=&evsel-&dispatch(base,&evbase,&tv_p);27&28&//处理timeout事件,对于超时的事件,将其放到就绪事件链表29&timeout_process(base);30&31&if&(base-&event_count_active)&{32&&&&&//处理就绪事件33&&&&&event_process_active(base);34&&&&&if&(!base-&event_count_active&&&&(flags&&&EVLOOP_ONCE))35&&&&&&&&&done&=&1;36&}&else&if&(flags&&&EVLOOP_NONBLOCK)37&&&&&done&=&1;38&39&}//end&while40&
3.3、timeout_next
&1&/*根据timer&heap中事件的最小超时时间,计算I/O&demultiplex的最大等待时间.&2&**为了及时处理timer事件,I/O&demultiplex的最大等待时间不应该超过timer事件中最小的超时时间,&3&**否则,timer事件就不能得到及时处理&4&*/&5&static&int&6&timeout_next(struct&event_base&*base,&struct&timeval&**tv_p)&7&{&8&&&&&struct&timeval&&9&&&&&struct&event&*10&&&&&struct&timeval&*tv&=&*tv_p;11&12&&&&&//如果没有timer事件,则直接返回13&&&&&if&((ev&=&min_heap_top(&base-&timeheap))&==&NULL)&{14&&&&&&&&&/*&if&no&time-based&events&are&active&wait&for&I/O&*/15&&&&&&&&&*tv_p&=&NULL;16&&&&&&&&&return&(0);17&&&&&}18&19&&&&&if&(gettime(base,&&now)&==&-1)20&&&&&&&&&return&(-1);21&22&&&&&//如果最小的timer事件已经超时,则清除tv,即I/O&demultiplex不应该等待.23&&&&&if&(evutil_timercmp(&ev-&ev_timeout,&&now,&&=))&{24&&&&&&&&&evutil_timerclear(tv);25&&&&&&&&&return&(0);26&&&&&}27&28&&&&&//更新I/O&demultiplex可以等待的最大时间:ev-&ev_timeout&-&now29&&&&&evutil_timersub(&ev-&ev_timeout,&&now,&tv);30&&&&&return&(0);31&}32&
3.4、dispatch函数调用底层I/O multiplex的dispatch函数,具体的实现可以参见epoll的实现epoll_dispatch。3.5、event_process_active
&1&/*处理就绪事件.&2&**就绪事件位于优先级队列中,低优先级通常比高优先级队列先处理,所以,&3&**高优先级队列可能饿死.&4&*/&5&static&void&6&event_process_active(struct&event_base&*base)&7&{&8&&&&&struct&event&*&9&&&&&struct&event_list&*activeq&=&NULL;10&&&&&int&i;11&&&&&short&12&13&&&&&for&(i&=&0;&i&&&base-&&++i)&{14&&&&&&&&&if&(TAILQ_FIRST(base-&activequeues[i])&!=&NULL)&{15&&&&&&&&&&&&&//一次只处理一个就绪事件链表16&&&&&&&&&&&&&activeq&=&base-&activequeues[i];17&&&&&&&&&&&&&break;18&&&&&&&&&}19&&&&&}20&21&&&&&assert(activeq&!=&NULL);22&23&&&&&//处理就绪事件链表上的所有事件24&&&&&for&(ev&=&TAILQ_FIRST(activeq);&&ev&=&TAILQ_FIRST(activeq))&{25&&&&&&&&&26&&&&&&&&&//先将事件从链表上删除27&&&&&&&&&if&(ev-&ev_events&&&EV_PERSIST)28&&&&&&&&&&&&&event_queue_remove(base,&ev,&EVLIST_ACTIVE);29&&&&&&&&&else30&&&&&&&&&&&&&event_del(ev);&//删除事件31&&&&&&&&&32&&&&&&&&&/*&Allows&deletes&to&work&*/33&&&&&&&&&ncalls&=&ev-&ev_34&&&&&&&&&ev-&ev_pncalls&=&&35&&&&&&&&&while&(ncalls)&{36&&&&&&&&&&&&&ncalls--;&//调用次数减137&&&&&&&&&&&&&ev-&ev_ncalls&=&38&&&&&&&&&&&&&//调用事件的回调函数39&&&&&&&&&&&&&(*ev-&ev_callback)((int)ev-&ev_fd,&ev-&ev_res,&ev-&ev_arg);40&&&&&&&&&&&&&if&(base-&event_break)41&&&&&&&&&&&&&&&&&return;42&&&&&&&&&}43&&&&&}44&}45&
4、Timer事件Timer事件的处理本身比较简单,不再赘述。5、signal事件5.1、socket pairLibevent通过socketpair,将signal事件与I/O事件完美的统一起来。Socketpair,简单的说就一对socket,一端用于写,一端用于读。工作方式如下:&为了与I/O事件统一起来,libevent内部使用了一个针对read socket的读事件。5.1.1、Socketpair的创建与信号事件的初始化工作都是在evsignal_init中完成的,而evsignal_init通过调用evutil_socketpair创建socketpair。对于Unix平台,有socketpair系统调用;对于Windows,则相对复杂一些,具体见evutil_socketpair函数的实现。5.2、evsignal_info在event_base内部有一个evsignal_info类型的字段sig,它是用于管理signal事件的核心数据结构:
&1&//evsignal.h&2&struct&evsignal_info&{&3&struct&event&ev_&&&&//内部socket读事件&4&int&ev_signal_pair[2];&&//对应socket&pair的两个socket描述符&5&int&ev_signal_&&//内部socket读事件是否已经加入注册链表&6&volatile&sig_atomic_t&evsignal_&//是否有信号发生&7&//信号事件链表数组,evsigevents[signo]表示注册信号signo的事件&8&struct&event_list&evsigevents[NSIG];&&9&//具体记录每个信号触发的次数,evsigcaught[signo]是记录信号&signo被触发的次数10&sig_atomic_t&evsigcaught[NSIG];11&&&&&12&//sh_old记录了原来的&signal&处理函数指针,当信号&signo&注册的&event&被清空时,需要重新设置其处理函数13&#ifdef&HAVE_SIGACTION14&struct&sigaction&**sh_15&#else16&ev_sighandler_t&**sh_17&#endif18&int&sh_old_19&};20&
5.3、主要函数5.3.1、evsignal_init主要完成evsignal_info的初始化,主要算法:
&1&int&2&evsignal_init(struct&event_base&*base)&3&{&4&evutil_socketpair(AF_UNIX,&SOCK_STREAM,&0,&base-&sig.ev_signal_pair);&5&base-&sig.sh_old&=&NULL;&6&base-&sig.sh_old_max&=&0;&7&&8&//事件发生次数设为0&9&base-&sig.evsignal_caught&=&0;10&memset(&base-&sig.evsigcaught,&0,&sizeof(sig_atomic_t)*NSIG);11&/*&initialize&the&queues&for&all&events&*/12&for&(i&=&0;&i&&&NSIG;&++i)13&TAILQ_INIT(&base-&sig.evsigevents[i]);14&15&evutil_make_socket_nonblocking(base-&sig.ev_signal_pair[0]);&//写端16&17&//设置内部读事件18&event_set(&base-&sig.ev_signal,&base-&sig.ev_signal_pair[1],&19&EV_READ&|&EV_PERSIST,&evsignal_cb,&&base-&sig.ev_signal);&//读端20&base-&sig.ev_signal.ev_base&=&base;21&22&//sig.ev_signal&==&EV_READ&|&EV_PERSIST&|&EVLIST_INTERNAL23&base-&sig.ev_signal.ev_flags&|=&EVLIST_INTERNAL;24&}
该函数的关键在于这里会设置libevent用于管理信号事件的内部读事件evsignal_info的ev_signal,并将该事件对应的文件描述符设为socket pair的读端。该函数由I/O multiplex的init函数调用。注:这里只是设置,而并没有注册socket pair的读事件(见下一节)。5.3.2、evsignal_add当调用event_add注册信号事件时,内部会先调用I/O multiplex的add函数,add函数又会调用evsignal_add,将事件加到evsignal_info内部的信号事件链表。然后再event_queue_insert将其添加到event_base的注册事件链表。
&1&int&2&evsignal_add(struct&event&*ev)&3&{&4&&&&&int&&5&&&&&struct&event_base&*base&=&ev-&ev_&6&&&&&struct&evsignal_info&*sig&=&&ev-&ev_base-&&7&&8&&&&&//信号事件与I/O事件是不相容的&9&&&&&if&(ev-&ev_events&&&(EV_READ|EV_WRITE))10&&&&&&&&&event_errx(1,&"%s:&EV_SIGNAL&incompatible&use",&__func__);11&&&&&//事件的信号12&&&&&evsignal&=&EVENT_SIGNAL(ev);13&&&&&assert(evsignal&&=&0&&&&evsignal&&&NSIG);14&&&&&if&(TAILQ_EMPTY(&sig-&evsigevents[evsignal]))&{15&&&&&&&&&event_debug(("%s:&%p:&changing&signal&handler",&__func__,&ev));16&17&&&&&&&&&//注册信号处理函数evsignal_handler18&&&&&&&&&//向socket&pair的写端写入一个字节的数据19&&&&&&&&&if&(_evsignal_set_handler(20&&&&&&&&&&&&&&&&&base,&evsignal,&evsignal_handler)&==&-1)21&&&&&&&&&&&&&return&(-1);22&23&&&&&&&&&/*&catch&signals&if&they&happen&quickly&*/24&&&&&&&&&evsignal_base&=&base;25&26&&&&&&&&&//添加内部socket读事件sig-&ev_signal27&&&&&&&&&if&(!sig-&ev_signal_added)&{28&&&&&&&&&&&&&if&(event_add(&sig-&ev_signal,&NULL))29&&&&&&&&&&&&&&&&&return&(-1);30&&&&&&&&&&&&&sig-&ev_signal_added&=&1;31&&&&&&&&&}32&&&&&}33&34&&&&&/*&multiple&events&may&listen&to&the&same&signal&*/35&&&&&//添加信号事件链表36&&&&&TAILQ_INSERT_TAIL(&sig-&evsigevents[evsignal],&ev,&ev_signal_next);37&38&&&&&return&(0);39&}40&
这里有两个地方需要注意,一是调用_evsignal_set_handler设置外部注册信号事件对应的信号的信号处理函数evsignal_handler:
&1&static&void&2&evsignal_handler(int&sig)&3&{&4&&&&&int&save_errno&=&&5&&6&&&&&//设置信号事件的发生次数&7&&&&&evsignal_base-&sig.evsigcaught[sig]++;&8&&&&&evsignal_base-&sig.evsignal_caught&=&1;&9&10&#ifndef&HAVE_SIGACTION11&&&&&signal(sig,&evsignal_handler);12&#endif13&14&&&&&/*&Wake&up&our&notification&mechanism&*/15&&&&&//向socket&pair的写端写数据16&&&&&send(evsignal_base-&sig.ev_signal_pair[0],&"a",&1,&0);17&&&&&errno&=&save_18&}
当用户注册信号事件对应的信号发生时,OS转到evsignal_handler函数,从而设置sig.evsignal_caught,并向socket pair的写端发送数据。二是通过调用event_add完成内部socket pair的读事件sig-&ev_signal的注册。最后,将(外部)事件添加到信号事件链表。5.3.2、与主循环结合信号事件完成了注册,libevent就会在主循环中,等待事件发生,并处理事件。为了理解,来看看具体I/O demultiplex的dispatch函数:
&1&static&int&2&epoll_dispatch(struct&event_base&*base,&void&*arg,&struct&timeval&*tv)&3&{&4&&&&&struct&epollop&*epollop&=&&5&&&&&struct&epoll_event&*events&=&epollop-&&6&&&&&struct&evepoll&*&7&&&&&int&i,&res,&timeout&=&-1;&8&&9&&&&&if&(tv&!=&NULL)10&&&&&&&&&timeout&=&tv-&tv_sec&*&1000&+&(tv-&tv_usec&+&999)&/&1000;11&12&&&&&if&(timeout&&&MAX_EPOLL_TIMEOUT_MSEC)&{13&&&&&&&&&/*&Linux&kernels&can&wait&forever&if&the&timeout&is&too&14&&&&&&&&&&*&see&comment&on&MAX_EPOLL_TIMEOUT_MSEC.&*/15&&&&&&&&&timeout&=&MAX_EPOLL_TIMEOUT_MSEC;16&&&&&}17&18&&&&&//等待I/O事件19&&&&&res&=&epoll_wait(epollop-&epfd,&events,&epollop-&nevents,&timeout);20&21&&&&&if&(res&==&-1)&{22&&&&&&&&&if&(errno&!=&EINTR)&{23&&&&&&&&&&&&&event_warn("epoll_wait");24&&&&&&&&&&&&&return&(-1);25&&&&&&&&&}26&&&&&&&&&//epoll_wait被信号中断27&&&&&&&&&evsignal_process(base);28&&&&&&&&&return&(0);29&&&&&}&else&if&(base-&sig.evsignal_caught)&{//发生了信号事件30&&&&&&&&&//处理信号事件31&&&&&&&&&evsignal_process(base);32&&&&&}33&//&34&}
epoll_dispatch函数调用epoll_wait函数等待I/O发生。然后,如果有信号事件发生,则调用evsignal_process处理信号事件,evsignal_process的逻辑比较简单,它只是将事件从注册事件链表转移到就绪事件链表。还记得evsignal_handler函数吗?它是所有(外部)信号事件对应的信号的信号处理函数,将实际的信号发生时,OS会转而执行evsignal_handler函数,而它便向socket pair的写端写数据,而读端收到数据。而此时,libevent的内部socket pair读事件已经完成注册。libevent正阻塞在epoll_wait处,当socketp pair读端收到数据时,libevent便从epoll_wait处返回。总之,signal事件通过socket pair,与I/O事件实现完美的统一。Libevent从epoll_wait返回后,它调用evsignal_process处理信号事件,然后调用event_active将I/O事件(包括内部的socket pair读事件)转移到就绪事件链表。Socket pair的读事件回调函数:
&1&static&void&2&evsignal_cb(int&fd,&short&what,&void&*arg)&3&{&4&static&char&signals[1];&5&#ifdef&WIN32&6&SSIZE_T&n;&7&#else&8&ssize_t&n;&9&#endif10&//接收数据11&n&=&recv(fd,&signals,&sizeof(signals),&0);12&if&(n&==&-1)13&event_err(1,&"%s:&read",&__func__);14&}
6、libevent的应用Libevent是一个非常优秀的开源网络库,它被许多其它开源程序使用。Memcache使用libevent作为底层的网络处理组件,并采用主线程(main thread,单一)+工作线程(work thread,多个)的多线程模型(这将在Memcached的分析中详细介绍)。&
阅读(...) 评论()

我要回帖

更多关于 错误代码31 9 的文章

 

随机推荐