心情有些崩溃,之前很抱有信心的一个offer,结果被通知已经招到人了。真的很难过,只能靠毛主席语录,来安慰自己。
不为敌之其势汹汹所吓倒,不为尚能忍耐的困难所沮丧,不为某些挫折而灰心,给与必要的耐心和持久,是完全必要的。
我们的同志在绝望中,要看到成绩,要看到光明,要提高我们的勇气。
黑暗即将过去,曙光就在前头,有利的情况和主动的恢复,产生于“再坚持一下”的努力之中。
今天看到了一篇相当不错的文章,对于skynet框架来说,服务也就是actor在modules列表中被创建,modules是存储so库句柄的列表,当创建一个服务时,就调用该列表的create操作。
而一个服务创建完成,一般不会执行任何逻辑,需要别人向它发出请求,才执行对应的逻辑,并在需要时将返回结果给请求者。所以,请求,回应和推送都是通过服务的消息队列来转发到另一个服务中。这个消息队列有两级,二级消息队列是供用工作线程调用的,一般工作线程会出队一个消息队列,然后从这个消息队列中出队一个消息(根据工作线程的权重来出队消息的个数),并找到该次级消息队列的所属服务,将消息当作该服务的callback函数的参数,来执行指定业务
skynet有几类线程?
4种,monitor线程用来检测节点内的消息是否堵住
timer线程运行定时器 ,唤醒因消息队列为空而阻塞的工作线程 —(生产者)
socket线程进行网络数据的收发——(生产者)
worker线程则负责对消息队列进行调用——(生产者和消费者)
所有的lua服务都依附于snlua的c模块,lua服务每次收到一个消息,就会产生一个协程,并通过协程来执行注册函数。
创建一个新的服务,首先找到对应服务的module,创建完module示例并完成初始化后,需要创建一个skynet_context上下文,并将module模块和这个context关联起来,最后放置到skynet_context list中
创建一个skynet_context服务时,会往slot列表中存放,callback一般在module的init函数中根据服务类型来创建。modules可以看作workflow中的WFactory类,skynet_context就是同一个模板创建的不同的任务。然后这些任务又是由handle_storage管理。
一个消息是如何被写进队列的:
向一个服务发消息,最终是通过调用skynet.send(异步)将消息插入到该服务的消息队列中,由于服务(context)只包含了一个指向这个队列的指针,所以对队列的操作不会影响该服务的上下文。因此,一个服务执行callback时,其他服务可以对队列进行操作。
如何启动一个c服务?
-
从modules列表中,查找对应的服务模块,如果找到则返回,否则到modules的path中去查找对应的so库,创建一个skynet_module对象(数据结构见上节),将so库加载到内存,并将访问该so库的句柄和skynet_module对象关联(_try_open做了这件事),并将so库中的xxx_create,xxx_init,xxx_signal,xxx_release四个函数地址赋值给skynet_module的create、init、signal和release四个函数中,这样这个skynet_module对象,就能调用so库中,对应的四个接口(_open_sym做了这件事)。
-
创建一个服务实例即skynet_context对象,他包含一个次级消息队列指针,服务模块指针(skynet_module对象,便于他访问module自定义的create、init、signal和release函数),由服务模块调用create接口创建的数据实例等。
-
将新创建的服务实例(skynet_context对象)注册到全局的服务列表中(见上节的handle_storage结构)。
-
初始化服务模块(skynet_module创建的数据实例),并在初始化函数中,注册新创建的skynet_context实例的callback函数
-
将该服务实例(skynet_context实例)的次级消息队列,插入到全局消息队列中。
经过上面的步骤,一个c服务模块就被创建出来了,在回调函数被指定以后,其他服务发送给他的消息,会被pop出来,最终传给服务对应的callback函数,最后达到驱动服务的目的。
网络事件
接到来自客户端的消息时,创建一个gate服务,用于接收socket发送过来的消息。
通过gate服务(work线程中)绑定一个端口,通过管道向socket线程中发送一个请求,向socket slot中里添加一个专门用于监听端口的socket,并且在epoll里添加这个socket的监听事件。在红黑树结点的对应时间的data里绑定了这个socket的指针,而这个结点对应的事件又包含了服务地址。
创建了监听端口的socket,并将其作为事件添加到红黑树上监听以后,当epoll监听到连接请求,就往socket_server中添加新的socket,此时socket线程会通知gate服务的次级消息队列,插入一个消息,告诉它有新的连接建立。并告诉gate这个新创建的socket在socket_server slot的id,gate在接收到新连接建立事件后,会创建一个lua服务(agent),并以这个slot中的id作为key,agent服务地址作为value存入到table。以便于agent服务要推送消息时,通过管道将数据发给socket线程,socket线程在通过slot找到对应的id,再去找到对应的事件(socket),就找到了连接,即socket文件描述符。向这个文件描述符中传数据到客户端。
大致流程就是如此,明天再看一些视频好好巩固一下。虽然知道了skynet框架,但是感觉对于找工作的帮助依旧不是很大,未来依旧迷茫。工作更看重的是工作经验,对于应届生还是相当惨烈的。
加油吧,什么都不做,也不会变得更好,那折腾一下会不会有点起色呢?