20212305 2023-2024-2 《移动平台开发与实践》第4次作业

20212305杨贯宇 2024-06-30 01:01:55

20212305 2023-2024-2 《移动平台开发与实践》第4次作业

1.实验内容

1.1本周学习内容

1.1.1Socket技术

Socket,也被称为“套接字”,是应用程序用于向网络发送请求或响应网络请求的机制,它允许不同主机或同一计算机上的进程之间进行通信。
在服务端,首先进行Socket的初始化,随后将其与特定端口绑定(bind),并对该端口进行监听(listen)。此时,服务端调用accept进入阻塞状态,等待客户端的连接请求。当客户端初始化一个Socket并尝试连接到服务器(connect)时,若连接成功,即建立了客户端与服务器之间的通信链路。
客户端随后发送数据请求,服务端接收并处理这些请求,之后将响应数据发送回客户端。客户端读取这些数据后,通信双方关闭连接,至此完成一次交互过程。
在使用TCP发送数据时,由于TCP连接已经建立,因此无需指定目标地址。相比之下,UDP是面向无连接的,每次发送数据时都需要明确指定接收方。

1.1.2 Webview控件

WebView控件是Android应用中用于展现网页内容的关键组件。它能够载入并呈现Web页面,同时兼容JavaScript执行、页面交互及其他Web技术。
WebView具备加载和展示Web页面的功能,涵盖HTML、CSS、JavaScript等网页元素。
在Android应用中,WebView控件被广泛用于展示网页内容,比如作为内置浏览器使用,或在混合开发应用中展示原生和Web内容。它为开发者提供了一个强大的工具,使得应用能够展示丰富的Web内容,并实现与用户的交互。

1.2实验目的

1.掌握Android平台上Socket编程的基本概念。
2.学习使用Kotlin语言实现Android Socket服务端和客户端。
3.理解TCP/UDP协议在Socket通信中的应用。

1.3实验环境

Android Studio
Kotlin编程语言
模拟器或真实Android设备

2.实验过程

新建两个项目,分别是服务器Server和客户端Client

img


img

2.1服务端实现

(1) 创建一个新的Android项目,并在项目中添加必要的权限,如INTERNET权限。

img

(2)编写服务端代码,创建一个ServerSocket监听指定端口。

img

完整代码如下:
MainActivity.kt

package com.example.project4_server

import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.activity.ComponentActivity
import java.util.concurrent.Executors

class MainActivity : ComponentActivity() {
    private lateinit var server: Server
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_server)
        server = Server { message ->
            runOnUiThread {
                displayMessage("Client: $message")
            }
        }
        Executors.newSingleThreadExecutor().execute {
            server.start()
        }

        val sendButton : Button = findViewById(R.id.buttonSend)
        sendButton.setOnClickListener {
            val messageInput : EditText = findViewById(R.id.editTextMessage)
            val message = messageInput.text.toString()
            if (message.isNotEmpty()) {
                server.sendMessage(message)
                displayMessage("Server(Me): $message")
                messageInput.text.clear()
            }
        }
    }

    private fun displayMessage(message: String) {
        var messageDisplay : TextView = findViewById(R.id.textViewMessage)
        messageDisplay.append("$message\n")
    }

    override fun onDestroy() {
        super.onDestroy()
        server.stop()
    }
}

activity_server.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/editTextMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter your message" />

    <Button
        android:id="@+id/buttonSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send" />

    <TextView
        android:id="@+id/textViewMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="Received Message"
        android:textStyle="bold" />

</LinearLayout>

Server.kt

package com.example.project4_server

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.PrintWriter
import java.net.ServerSocket

class Server(private val messageListener: (String) -> Unit) {
    private val serverSocket = ServerSocket(2104)
    private lateinit var writer: PrintWriter
    private lateinit var reader: BufferedReader

    fun start() {
        while (true) {
            val clientSocket = serverSocket.accept()
            GlobalScope.launch(Dispatchers.IO) {
                val outputStream = clientSocket.getOutputStream()
                writer = PrintWriter(outputStream, true)
                val inputStream = clientSocket.getInputStream()
                reader = BufferedReader(InputStreamReader(inputStream))
                writer.println("恭喜您,与客户端连接成功!!")
                while (true) {
                    val messageFromServer = reader.readLine()
                    if (messageFromServer != null) {
                        messageListener.invoke(messageFromServer)
                    }
                }
            }
        }
    }

    fun sendMessage(message: String) {
        GlobalScope.launch(Dispatchers.IO) {
            writer.println(message)
        }
    }

    fun stop() {
        serverSocket.close()
    }
}

运行结果如图:

img

2.2客户端实现

(1) 编写客户端代码,创建一个Socket对象连接服务端。

img

基本和服务端差不多
完整代码如下:
activity_client.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">

    <EditText
        android:id="@+id/editTextMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="Enter your message" />

    <Button
        android:id="@+id/buttonSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Send" />

    <TextView
        android:id="@+id/textViewReceivedMessage"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:text="Received Message"
        android:textStyle="bold" />

</LinearLayout>

MainActivity.kt

package com.example.project4_client

import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.activity.ComponentActivity

class MainActivity : ComponentActivity() {
    private lateinit var client: Client
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_client)

        client = Client { message ->
            runOnUiThread {
                displayMessage("Server: $message")
            }
        }
        client.connect()

        val sendButton : Button = findViewById(R.id.buttonSend)
        sendButton.setOnClickListener {
            val messageInput : EditText = findViewById(R.id.editTextMessage)
            val message = messageInput.text.toString()
            if (message.isNotEmpty()) {
                client.sendMessage(message)
                displayMessage("Client(Me): $message")
                messageInput.text.clear()
            }
        }
    }

    private fun displayMessage(message: String) {
        var messageDisplay : TextView = findViewById(R.id.textViewReceivedMessage)
        messageDisplay.append("$message\n")
    }

    override fun onDestroy() {
        super.onDestroy()
        client.disconnect()
    }
}

Cilent.kt

package com.example.project4_client

import java.io.BufferedReader
import java.io.InputStreamReader
import java.io.PrintWriter
import java.net.Socket
import kotlinx.coroutines.*

class Client(private val messageListener: (String) -> Unit) {
    private lateinit var clientSocket: Socket
    private lateinit var writer: PrintWriter
    private lateinit var reader: BufferedReader

    fun connect() {
        GlobalScope.launch(Dispatchers.IO) {
            clientSocket = Socket("192.168.31.137", 2104)
            val outputStream = clientSocket.getOutputStream()
            writer = PrintWriter(outputStream, true)
            writer.println("恭喜您,与服务器连接成功!!")
            val inputStream = clientSocket.getInputStream()
            reader = BufferedReader(InputStreamReader(inputStream))
            while (true) {
                val messageFromServer = reader.readLine()
                if (messageFromServer != null) {
                    messageListener.invoke(messageFromServer)
                }
            }
        }
    }
    fun sendMessage(message: String) {
        GlobalScope.launch(Dispatchers.IO) {
            writer.println(message)
        }
    }
    fun disconnect() {
        writer.close()
        reader.close()
        clientSocket.close()
    }

}

最终效果如下方视频所示(失败了):

3.学习中遇到的问题及解决

问题1:想要用两个虚拟设备,一个作客户端,一个作服务器端,但是第二个虚拟设备始终无法正常启动

img


问题1解决方案:我放弃了,改用自己的手机,AndroidStudio连接手机的教程在下面这个链接:
https://blog.csdn.net/Hua_TZ/article/details/136424230?ops_request_misc=&request_id=&biz_id=102&utm_term=Android%20studio%E5%A6%82%E4%BD%95%E8%BF%9E%E6%8E%A5%E8%87%AA%E5%B7%B1%E7%9A%84%E6%89%8B%E6%9C%BA&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-0-136424230.142^v100^pc_search_result_base9&spm=1018.2226.3001.4187
问题2:无法正常传输数据,我的手机总是卡退
问题2具体描述:这个问题我无法解决,我甚至把我的手机连到其他实验成功的同学的电脑上,也失败了。手机作为服务器端时,发送信息后就会自动退出程序;手机作为客户端时,直接闪退客户端程序……

4.学习感悟、思考等

通过本次实验,我深刻领悟了Android平台上Socket编程的核心概念,并掌握了如何在Android应用开发中运用Kotlin语言实现Socket的服务端与客户端功能。我熟悉了ServerSocket类和Socket类的基本应用,其中ServerSocket用于在服务端监听特定端口,而Socket则用于在客户端与服务端之间建立连接。此外,我还学会了在Socket编程中如何发送与接收数据,涵盖了字符串数据的发送与接收,以及利用输入输出流进行数据交换的技巧。
实验结束后,虽然没能成功,但是我对Android平台上的Socket编程有了更为深刻的理解,并掌握了实际应用中的开发技能与实战经验。同时,这次实验也加深了我对TCP/UDP协议在Socket通信中所起作用的理解,为我未来在网络编程领域的进一步工作与学习奠定了坚实的基础。

...全文
202 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

102

社区成员

发帖
与我相关
我的任务
社区描述
实验报告
android 高校
社区管理员
  • blackwall0321
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧