前言,今天写一写就离题了QQ,前面用ktor架websocket,在手机app接起来,复习一下channel的特性,後面离题讲了手机怎麽接到localhost
简单介绍,webSocket是一个客户端和服务器之间进行双向持续对话,server也可以发讯息给client,不像restful api要由client主动发出请求。
其他关於websocket的介绍,自己上网找,网上资源很多,我就直接带code
首先,网上大多会告诉你,这是免费的,但是他的连线极其不稳,有时还连不上
//刚刚测还是连不上
ws://echo.websocket.org
那android本身其实能用MockWebServer去模拟server,但我偏不,我要用ktor自己架,我不只要自己架,我还会告诉你怎麽从实机连线到电脑的localhost
MockWebServer,好像原本是测试用途,我不喜欢这样混用,所以用ktor架了
那用ktor要怎麽架websocket呢?
看文档,对的喔我也都是看文档的哈哈哈哈哈
//intelliJ
fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)
@Suppress("unused")
fun Application.module() {
val scope = CoroutineScope(Job())
install(WebSockets)
routing {
webSocket("/chat") {
send("You are connected!")
randomResponse(scope, this)
for(frame in incoming) {
frame as? Frame.Text ?: continue
val receivedText = frame.readText()
send("You said: $receivedText")
}
}
}
}
fun randomResponse(scope: CoroutineScope, socket:DefaultWebSocketServerSession){
val randomSample = arrayOf(
"I am hungry",
"Harry Potter",
"ciao, mon amigo",
"To be or not to be",
"Android developer"
)
scope.launch {
while(isActive){
delay(1500)
socket.send(randomSample[(0..4).random()])
yield()
}
}
}
除了randomResponse以外,其他都跟文档一样,这整串就是,帮我开启一个websocket,建立一个"/chat"的路径(url path),当有人连上这个路径时,先告诉她"You are connected!", 接着透过coroutine建立一个randomResponse方法,一直传讯息给client,最後再用回圈针对收到的讯息做系统回复
简单,好懂
执行後,建议先用网页别人写好的websocket测试,随便找个测试网站,给他ws://localhost:8080/chat`试试,如果收发都没问题就能进下一步
fragment我用一个textview来接
//Android studio
class SocketFragment : Fragment() {
private lateinit var binding:FragmentSocketBinding
private val mAdapter = ChatAdapter()
private val viewModel by viewModels<SocketViewModel>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_socket, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding = FragmentSocketBinding.bind(view)
lifecycleScope.launch {
viewModel.messageChannel.consumeEach {
Timber.d("in fragment $it")
binding.allMsg.text = StringBuilder(binding.allMsg.text).append(it)
binding.allMsg.invalidate()
}
}
binding.sentMsg.setOnClickListener {
viewModel.sentMessage( binding.ed.text.toString() )
binding.ed.setText("")
}
}
}
socket在viewModel实例,比较好控制生命周期
class SocketViewModel: ViewModel() {
private var mWebSocket: WebSocket? = null
private val mWbSocketUrl = "ws://127.0.0.1:8080/chat"
val messageChannel = Channel<String>()
init {
initSocket()
}
fun initSocket() {
val mClient = OkHttpClient.Builder()
.pingInterval(10, TimeUnit.SECONDS)
.build()
val request: Request = Request.Builder()
.url(mWbSocketUrl)
.build()
mWebSocket = mClient.newWebSocket(request, object : WebSocketListener(){
override fun onMessage( webSocket: WebSocket, text: String) {
super.onMessage(webSocket, text)
viewModelScope.launch {
messageChannel.send(text + "\n")
Timber.d("receive message $text")
}
}
override fun onOpen(webSocket: WebSocket, response: Response) {
super.onOpen(webSocket, response)
Timber.d("success connect")
}
override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
super.onClosing(webSocket, code, reason)
mWebSocket?.close(code, reason)
mWebSocket = null
}
override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
super.onFailure(webSocket, t, response)
Timber.e("fail connect")
Timber.e(response?.message)
}
})
}
fun sentMessage(s:String){
mWebSocket?.send(s)
}
override fun onCleared() {
super.onCleared()
messageChannel.cancel()
mWebSocket?.cancel()
mWebSocket = null
}
}
可以看到,我用channel在viewModel和fragment之间传讯息,记得channel的特性吗?
不知道的,可以先看这篇
先给效果,大概长这样
private val mWbSocketUrl = "ws://10.0.2.2:8080/chat"
在chrome的网址列输入chrome://inspect/#devices
确定手机usb侦错有打开
确定Remote Target有设备,可打开手机浏览器确定网页也有被抓到
大概长这样,我是把chrome调成暗色,所以你们画面可能会是白底的
设置port, ip address
其实我也有些不懂,目前测试
直播流接Discover USB devices
就好
websocket要两个都接
接法是
Discover USB devices
Discover network targets
两个都是接8080的就可以了,其他的是我之前接直播流用的port
private val mWbSocketUrl = "ws://127.0.0.1:8080/chat"
private val mWbSocketUrl = "ws://电脑ip:8080/chat"
大家应该都知道网路有七层吧
不知道的,也能做,在这里讲网路分层就离题太远了
anyway, 我有时开发会忘记带usb线,这时我就会用无线侦错(跳过不讲无线侦错部分),那方法二是透过chrome的开发功能连接,无线时要怎麽办呢?
从网域连线~~~~
首先把电脑和手机连到同一个wifi,请确定wifi是可信任的,因为等等要开防火墙的port
在cmd下ipconfig拿到电脑的ip位址
window控制台
进阶设置>输入规则>新增规则
选择
post
连线设置
设置,如果建议取消公用,然後将wifi加入至家用或工作
建立好就会这样
电脑的ip每次都会更改,可以参考这篇设置ip,方法三我也是参考这篇的
>>: Day 15 | 魔术方块AR游戏开发Part4 - 面的旋转(下)+游戏机制
本系列文记录了我近三年的转变,系列文的内容基本上都会与资讯科技扯上边,希望本文也可以对与我有相似背景...
能载舟,能覆舟 前几篇似乎说了很多 Rails 的坏话,但其实 Rails 是一套工具,工具没有好坏...
再两天 ~!! 在铁人赛的最後,我想要给各位带来的是噪声地形的演算~ 之所以想要写这个题目,原因是...
成为武林高手的第一步-轻小说阅读模式启动【ON】 ------------------------ ...
升上高中也有专题研究的学分。为了找到适合的题目,我和同个专研的同学一起到师大资工(和科学班合作的校系...