scala案例akka-rpc通信

master

package com.doit.demo02

import akka.actor.{Actor, ActorSystem, Props}
import com.typesafe.config.ConfigFactory

import scala.collection.mutable
import scala.concurrent.duration._
/**
  * @author 向阳木
  * @date 2020/09/14/ 17:36
  * @Description:
  *              Master客户端  接受并保存Worker的信息 启动定时器,检测Worker的心跳机制,并移除超时Worker
  */
class Master extends Actor{
  //将数据封装到map中
  val idToWorkerMap = new mutable.HashMap[String,WorkerInfo]()

  //重写preStart 启动定时器
  override def preStart(): Unit = {
    //启动定时器,定期检测
    /**
      * 第一个参数 自动启动的时间
      * 第二个参数 检测的时间的间隔
      * 第三个参数 发给自身做中转转发
      * 第四个参数  worker时间和本地时间差
      */
    import context.dispatcher
    context.system.scheduler.schedule(0.milliseconds , 15000.milliseconds , self ,CheckTimeOutWorker  )
  }
  //接受消息
  //
  override def receive: Receive = {
    // 接受worker的注册信息
    case RegisterWorker(workerId,memory,cores) => {
      //接受传过来的数据,并将数据封装
      val workerInfo = new WorkerInfo(workerId, memory, cores)
      if (!idToWorkerMap.contains(workerId)) {
        idToWorkerMap.put(workerId,workerInfo)
      }
      //向worker发送注册成功的消息
      sender() ! RegisteredWorker
    }

      //接受Worker 周期性心跳信息 worker 发来的消息携带的只有workerID 信息
      //然后根据当前的时间来给心跳时间赋值
    case HearBeat(workerId) => {
      //根据workerId 到map中找对应的workerInfo ,然后更新最新一次心跳时间
      val workerInfo: WorkerInfo = idToWorkerMap(workerId)
      //获取当前时间
      val currenTime: Long = System.currentTimeMillis()
      //更新workerInfo 的时间
      workerInfo.lastHearBeatTime = currenTime
    }

      //匹配检测超时的信息
       //mater 每15s 给自己发送一次
    case CheckTimeOutWorker =>{
      //检测所有超时的worker
      val deadWorkers: Iterable[WorkerInfo] = idToWorkerMap.values.filter(w => System.currentTimeMillis() - w.lastHearBeatTime > 10000)
      //移除超时的worker
      deadWorkers.foreach(w =>{
        //从map中移除
        idToWorkerMap.remove(w.workerId)
      })
      //打印此时正在工作的worker的数量
      println(s"current alive worker size is ${idToWorkerMap.size}")

    }

  }
}
object Master{
  val MASTER_ACTOR_SYSTEM = "MASTER_ACTOR_SYSTEM"
  val MASTER_ACTOR = "MASTER_ACTOR"

  def main(args: Array[String]): Unit = {
   /// val masterHost = args(0)
    val masterHost = "localhost"
  //  val masterPort = args(1).toInt
    val masterPort = 8888

    val configStr = s"""
                       |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
                       |akka.remote.netty.tcp.hostname = $masterHost
                       |akka.remote.netty.tcp.port = $masterPort
                       |""".stripMargin

    val config = ConfigFactory.parseString(configStr)

    //先创建actorSystem 单例
    val system: ActorSystem = ActorSystem(MASTER_ACTOR_SYSTEM , config)
    //创建actor
    system.actorOf(Props[Master] , MASTER_ACTOR)
  }



}

woker

package com.doit.demo02

import java.util.UUID

import akka.actor.{Actor, ActorSelection, ActorSystem, Props}
import com.typesafe.config.{Config, ConfigFactory}

import scala.concurrent.duration._

/**
  * @author 向阳木
  * @date 2020/09/14/ 17:40
  * @Description: Worker 客户端
  *                    和Master建立连接,并向其发送注册信息  建立定时器,定期向Master汇报自身信息,并发送心跳
  */
class Worker(val masterHost:String , val masterPort:Int , var workerMemory:Int , var workerCores:Int) extends Actor{
  //定义 workerId 保证唯一性
  val workerId = UUID.randomUUID().toString
// 将此变量定义为全局变量
  var masterRef: ActorSelection = null
  //重写preStart方法  在receive 方法之前执行一次
  override def preStart(): Unit = {
    //和master建立连接(拿到master的连接)
   masterRef = context.actorSelection(s"akka.tcp://${Master.MASTER_ACTOR_SYSTEM}@$masterHost:$masterPort/user/${Master.MASTER_ACTOR}")
    //向master发送消息
    masterRef ! RegisterWorker(workerId , workerMemory ,workerCores)
  }

  //接收master发来的消息
  override def receive: Receive = {
    //从master发来的 注册成功的信息
    case RegisteredWorker =>{
      //接收注册成功的信息后 在worker内部开启一个定时器,定期向Mater发送心跳
      //导入隐式转换
      import context.dispatcher
      context.system.scheduler.schedule(0.milliseconds , 10000.milliseconds , self , SendHearBeat)
    }
    case SendHearBeat =>{
      //用if 判断逻辑
      //向master 发送心跳
      masterRef ! HearBeat(workerId)
    }

  }
}
object Worker{
  // 定义worker system名 和 actor的名
  val WORKER_ACTOR_SYSTEM = "WORKER_ACTOR_SYSTEM"
  val WORKER_ACTOR = "WORKER_ACTOR"

  def main(args: Array[String]): Unit = {
      //接收参数
    /*val masterHost = args(0)
    val masterPort = args(1).toInt
    val workerHost = args(2)
    val workerPort = args(3).toInt
    val workerMemory = args(4).toInt
    val workerCores = args(5).toInt*/

    val masterHost = "localhost"
    val masterPort = 8888
    val workerHost = "localhost"
    val workerPort = 9999
    val workerMemory = 4086
    val workerCores = 8

    // 定义 configStr 的变量
    val configStr =
      s"""
         |akka.actor.provider = "akka.remote.RemoteActorRefProvider"
         |akka.remote.netty.tcp.hostname = $workerHost
         |akka.remote.netty.tcp.port = $workerPort
         |""".stripMargin
    //获得config
    val config: Config = ConfigFactory.parseString(configStr)
      //获得actorSystem
    val system: ActorSystem = ActorSystem(WORKER_ACTOR_SYSTEM , config)
    //获得actor
    system.actorOf(Props(new Worker(masterHost , masterPort , workerMemory ,workerCores)) , WORKER_ACTOR)

  }



}

workerInfo

package com.doit.demo02

/**
  * @author 向阳木
  * @date 2020/09/14/ 17:48
  * @Description:
  *              封装worker数据
  */
class WorkerInfo(val workerId:String , var memory:Int , var cores:Int) {

  var lastHearBeatTime:Long = _

}

Messages

package com.doit.demo02
/**
  * @author 向阳木
  * @date 2020/09/14/ 17:58
  * @Description: 封装master和worker 以及自身内部的通信数据
  */
//Master发给自己的检测信息
case object CheckTimeOutWorker

//worker 发送给Master的注册消息
case class RegisterWorker(workerId:String , memory:Int , cores:Int)

//master向worker发送注册成功的信息
//case object 没有参数输入 是一个多例的
case object RegisteredWorker

//worker 发送给 master的心跳消息
case class HearBeat(workerId:String)

//worker 发送给master的心跳信息 内部中间转发给自身的信息
case object SendHearBeat
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特点,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值