开发者学堂课程【Scala 核心编程 - 进阶:小黄鸡的客户端和服务器端通讯】学习笔记,与课程紧密连接,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/610/detail/9122
小黄鸡的客户端和服务器端通讯
内容介绍
一、课前引入
二、建立循环
三、总结 Akka 网络编程-小黄鸡客服
一、课前引入
上次课将主程序中的 ActorSystem 和 Actor 都创建完成,下一步就是探索如何发消息当我们拿到信息后,下一步可以开始写一个循环
二、建立循环
1.填写代码
客户端可以发送消息给服务器,为了简单,所以直接写入 true ,可也以加入别的信息
While (true) {
println (“请输入要咨询的问题”)
//这时候会得到输入的消息例如
val mes = StdIn.readLine()
//将发送消息的任务交给下列代码做比较合理
override def receive:Receive = {
case “start”=>println(“start,客户端运行,可以咨询问题”)
//因此,customerActorRef 中发送的消息发送到了 receive 处
customerActorRef ! mes
//接下来进行匹配,当接收到下列代码时可以知道,有人发了一个字符串过来
case mes:String=>{
//这时候将消息转发给服务器端(小黄鸡客服),因为此时持有
serverActorRef ,所以发送变得简单清晰,可以直接发送
serverActorRef !mes
//切记不可像上面这样发送,因为它本身是一个字符串,在发送的时候,一般会以对象的形式而且是序列化的,对方才能更好地得到信息。而且发送没有序列化的字符串意义不大,所以要做成一个对象,才能区分。假设未来还有新的形式,就会无法区分。因此需要写一个协议
2.创建协议
(1)新建文件
在 common 中新建文件取名为 MessageProtocol (Protocol 是协议的意思)
(2)构建协议
//使用样例类来构建协议
//有两个协议,一个是客户端发给服务器的协议(以序列化的对象的形式发送),显然最好的方式是样例类,因为样例类默认实现了序列化
case class clientMessage(mes : String)
//传入的参数默认会成为这一个对象的只读属性
serverActorRef !ClientMessage(mes)
//mes 后面也可以加入更多信息;此时 ClientMessage(mes) 发送的是它的对象,使用 clientMessage case class apply,发送消息后,服务器端需要立即接收并处理消息,通过示意图,可以增加学习的逻辑性和可操作性
//CustomerActor 发送咨询问题给
YellowChickenServer-actor是通过 ClientMessage 发送的,接收到 ClientMessage 后接着写
case ClientMessage (mes)=>
//使用 match --case 匹配
//匹配时可以精准匹配也可以模糊匹配,上面使用精准匹配,此时可以使用其他相关技术,一般来说,想要做一个完整的小黄鸡,不能在这里匹配,此处的匹配是一个话题,类似于词法和语法运行,会有相关的技术
case“大数据学费”=> sender()!“35000RMB”
//因为35000发出去后对方接收不方便,所以需要添加一个新的样例类的协议,serverMessage
//服务器端发送给客户端的协议(样例类)
case class ServerMessage(mes:String)
//接下来要构建一个 serverMessage 的对象
case“大数据学费”=> sender()!ServerMessage(“35000RMB”)
//在实际运用中 client 和 common 交给客户端运行,common 和 server 放到另一边运行
case“学校地址”=> sender()!ServerMessage(“北京昌平XX路XX大楼”)
case“学习什么技术”=> sender()!ServerMessage(“大数据 前端 python”)
//如果随便发了一个,则可以设置万能回复
Case_=> sender()!ServerMessage(“你说的啥子~”)
//如果接收到服务器端的回复
case ServerMessage(mes)=>{
//用到偏函数的对象提取器
Println(“收到小黄鸡客服(server):$mes”)
//此时已经完成,这是一个简单的交互。扩展后可以做成一个聊天系统。因为协议用到样例类,做的比较简单。
3.启动服务器端
发现出现错误,需要在 case 前后添加{};找到错误后继续运行。发现“小黄鸡客服开始工作了”,打开客服运行,看到“客户端运行,可以咨询问题”,在下方输入“学校地址”,报出错误。重新检查一次流程,找到问题继续运行。
输入“what”会回复“你说的啥子~”表明已经识别,再次输入“学校地址”会出现“北京昌平XX路XX大楼”,输入“大数据学费”会回复“35000RMB”,输入“学习什么技术”会回复“大数据 前端 python”,输入“jack”会回复“你说的啥子~”,流程到此结束。
三、总结 Akka 网络编程-小黄鸡客服
1.需求分析
(1)服务器端进行监听(9999)
(2)客户端可以通过键盘输入,发送咨询问题给小黄鸡客服(服务端)
(3)小黄鸡(服务端)回答客户的问题
2.程序框架图
(1)服务器框架图说明:
先写服务器端原因是服务器先运行;主程序创建后不启动则无法监听; MailBox 为服务器邮箱
(2)客户端框架图说明:
创建客户 Actor【CustomerActor】配置时必须持有或得到YellowChickenServerActorRef 才能发送信息;MailBox 为客户端邮箱
(3)整体框架图说明:
客户端发送咨询问题:
直接将问题发送至服务器邮箱
服务器接收问题:
服务器邮箱通过 receive 方法,从邮箱中提取信息
服务器回复消息:
可以通过 sender 的方法发送至对方的邮箱
3.功能实现(走代码)
写入 client ,common,server 目录
先写 server 端的代码
//YellowChickenServer.scala
package com.atguigu.akka.yellowchicken.server
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import com.atguigu.akka.yellowchicken.common. {ClientMessage, ServerMessage;}
import com.typesafe.config.ConfigFactory
class YellowChickenServer extends Actorl{
override def receive:Receive= {
case "start" => println("start 小黄鸡客服开始工作了...")
case ClientMessage(mes)=>{
mes match {
case "大数据学费" => sender() ! ServerMessage("35000RMB")
case "学校地址" => sender() ! ServerMessage("北京昌平xx路xx大楼")
case "学习什么技术" => sender() ! ServerMessage("大数据 前端python")
case_ => sender0()! ServerMessage(" 你说的啥子~")
接着写客户端的代码
//CustomerActor.scala
package com.atguigu.akka. yellowchicken.client
importakka.actor.{Actor,ActorRef,ActorSelection, ActorSystem, Props}
import com.atguigu.akka.yellowchicken.common. {ClientMessage, ServerMessage}
import com.typesafe.config.ConfigFactory
import scala.io.StdIn
class CustomerActor(serverHost:String,serverPort: Int) extends Actor {
//定义一个YellowChickenServerRef
var serverActorRef: ActorSelection =_
//在 Actor 中有一个 PreStart 方法,他会在 actor 送行前执行
//在 akka 的开发中,通常将初始化的工作,放在 preStart 方法override def preStart(): Unit= {
println("preStart()执行 ")
serverActorRef
context.actorSelection(s"akka.tcp://Server@${serverHost};:${ serverPort}/user/YellowChickenServer")
最后写协议
协议是至关重要的,没有协议的情况下,通讯会变得十分麻烦。当 client 发送更多信息时,例如客户端是哪一个。
正因此时没有管理,让两个客户能够通讯,应该怎么做。客户端发的消息必须要指定我是谁以及我发给谁,然后用一个 map 来管理,就会变得清晰。
写上几行代码就能扩展起来,相当于把小黄鸡当做一个中转站。例如一个北京人和一个天津人不能直接对话,需要用到公网。
所以协议在此可以扩展。
//MessageProtocol.scala