广告
返回顶部
首页 > 资讯 > 移动开发 >Android Socket 简单介绍
  • 847
分享到

Android Socket 简单介绍

android 2023-09-23 17:09:46 847人浏览 八月长安
摘要

文章目录 前言一、Socket是什么?百度百科的解释我自己的理解 二、简单示例1.服务端2.客户端3.布局4.实现 参考总结 前言 最近需求需要使用Socket进行通讯,我在工作

文章目录


前言

最近需求需要使用Socket进行通讯,我在工作后的安卓开发中没有接触过,所以有了这篇文章;
写的时候想起来好像上大学的时候学过,后面一直没用忘记了;
之前公司同事的男朋友也在写这个来着,我当时还嘲笑怎么还会有人用这个,现在自己遇到了🐕;


一、Socket是什么?

百度百科的解释

所谓套接字(Socket),就是对网络中不同主机上的应用进程之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,提供了应用层进程利用网络协议交换数据的机制。从所处的地位来讲,套接字上联应用进程,下联网络协议栈,是应用程序通过网络协议进行通信的接口,是应用程序与网络协议栈进行交互的接口。

套接字Socket=(IP地址:端口号),套接字的表示方法是点分十进制的lP地址后面写上端口号,中间用冒号或逗号隔开。每一个传输层连接唯一地被通信两端的两个端点(即两个套接字)所确定。例如:如果IP地址是210.37.145.1,而端口号是23,那么得到套接字就是(210.37.145.1:23)

我自己的理解

分客户端与服务端,socket以服务端的ip地址和约定好的端口号进行组合得到套接字进行一个两端的相互连接,达到能够互相收发消息的一个目的。

二、简单示例

下面的代码将演示如何在一个app中实现服务端和客户端的简单示例

1.服务端

先创建抽象的ServerCallback

interface ServerCallback {    //接收客户端的消息    fun receiveClientMsg(success: Boolean, msg: String)    //其他消息,例如有客户端连接和发送消息成功等    fun otherMsg(msg: String)}

然后创建SocketServer来管理服务端的连接

代码如下:

import Android.util.Logimport java.io.IOExceptionimport java.io.InputStreamimport java.io.OutputStreamimport java.net.ServerSocketimport java.net.Socketobject SocketServer {    private val TAG = SocketServer::class.java.simpleName    private const val SOCKET_PORT =        7878    private var socket: Socket? = null    private var serverSocket: ServerSocket? = null    private lateinit var mCallback: ServerCallback    private lateinit var outputStream: OutputStream    var result = true        fun startServer(callback: ServerCallback): Boolean {        Log.i(TAG, "startServer: ")        mCallback = callback        Thread {            try {                serverSocket = ServerSocket(SOCKET_PORT)                while (result) {                    socket = serverSocket?.accept()                    mCallback.otherMsg("${socket?.inetAddress} to connected")                    ServerThread(socket!!, mCallback).start()                }            } catch (e: IOException) {                e.printStackTrace()                result = false            }        }.start()        return result    }        fun stopServer() {        Log.i(TAG, "stopServer: ")        socket?.apply {            shutdownInput()            shutdownOutput()            close()        }        serverSocket?.close()    }        fun sendToClient(msg: String) {        Thread {            if (socket!!.isClosed) {                Log.e(TAG, "sendToClient: Socket is closed")                return@Thread            }            outputStream = socket!!.getOutputStream()            try {                outputStream.write(msg.toByteArray())                outputStream.flush()                mCallback.otherMsg("toClient: $msg")                Log.d(TAG, "发送到客户端成功")            } catch (e: IOException) {                e.printStackTrace()                Log.e(TAG, "向客户端发送消息失败")            }        }.start()    }    class ServerThread(private val socket: Socket, private val callback: ServerCallback) :        Thread() {        override fun run() {            val inputStream: InputStream?            try {                inputStream = socket.getInputStream()                val buffer = ByteArray(1024)                var len: Int                var receiveStr = ""                if (inputStream.available() == 0) {                    Log.e(TAG, "inputStream.available() == 0")                }                while (inputStream.read(buffer).also { len = it } != -1) {                    receiveStr += String(buffer, 0, len, Charsets.UTF_8)                    if (len < 1024) {                        callback.receiveClientMsg(true, receiveStr)                        receiveStr = ""                    }                }            } catch (e: IOException) {                e.printStackTrace()                e.message?.let { Log.e("socket error", it) }                callback.receiveClientMsg(false, "")            }        }    }}

可以看到我们在通过startServer方法初始化ServerSocket时,只使用到了SOCKET_PORT,这个ServerSocket方法接收一个端口号,不接收ip,因为它将作为服务端
ServerSocket方法的注释译文: 创建绑定到指定端口的服务器套接字。端口号为0表示端口号是自动分配的,通常是从临时端口范围分配的。然后可以通过调用getLocalPort来检索这个端口号。传入连接指示(连接请求)的最大队列长度设置为50。如果连接指示在队列已满时到达,则拒绝连接。

2.客户端

同样我们创建一个抽象的 ClientCallback

interface ClientCallback {    //接收服务端的消息    fun receiveServerMsg(msg: String)    //其他消息    fun otherMsg(msg: String)}

然后创建SocketClient来管理服务端的连接

代码如下:

import android.util.Logimport java.io.IOExceptionimport java.io.InputStreamimport java.io.InputStreamReaderimport java.io.OutputStreamimport java.net.Socketimport java.util.Localeobject SocketClient {    private val TAG = SocketClient::class.java.simpleName    private var socket: Socket? = null    private var outputStream: OutputStream? = null    private var inputStreamReader: InputStreamReader? = null    private lateinit var mCallback: ClientCallback    private const val SOCKET_PORT = 7878        fun connectServer(ipAddress: String, callback: ClientCallback) {        mCallback = callback        Thread {            try {                socket = Socket(ipAddress, SOCKET_PORT)                ClientThread(socket!!, mCallback).start()            } catch (e: Exception) {                e.printStackTrace()            }        }.start()    }        fun closeConnect() {        try {            inputStreamReader?.close()            outputStream?.close()            socket?.apply {                shutdownInput()                shutdownOutput()                close()            }            Log.d(TAG, "关闭连接")        }catch (e: Exception){            e.printStackTrace()        }    }        fun sendToServer(msg: String) {        Thread {            if (socket!!.isClosed) {                Log.e(TAG, "sendToServer: Socket is closed")                return@Thread            }            outputStream = socket?.getOutputStream()            try {                outputStream?.write(msg.toByteArray())                outputStream?.flush()                mCallback.otherMsg("toServer: $msg")                Log.e(TAG, "向服务端发送消息成功")            } catch (e: IOException) {                e.printStackTrace()                Log.e(TAG, "向服务端发送消息失败")            }        }.start()    }    class ClientThread(private val socket: Socket, private val callback: ClientCallback) : Thread() {        override fun run() {            val inputStream: InputStream?            try {                inputStream = socket.getInputStream()                val buffer = ByteArray(1024)                var len: Int                var receiveStr = ""                if (inputStream.available() == 0) {                    Log.e(TAG, "inputStream.available() == 0")                }                while (inputStream.read(buffer).also { len = it } != -1) {                    receiveStr += String(buffer, 0, len, Charsets.UTF_8)                    if (len < 1024) {                        callback.receiveServerMsg(receiveStr)                        receiveStr = ""                    }                }            } catch (e: IOException) {                e.printStackTrace()                e.message?.let { Log.e("socket error", it) }                callback.receiveServerMsg( "")            }        }    }}

可以看到我们在客户端通过connectServer方法连接服务端时,使用了Socket方法,它接收了一个ip和一个约定好的端口号,这里的ip就是服务端的ip
Socket方法的注释译文为: 创建流套接字并将其连接到指定主机上的指定端口号。如果指定的主机为空,则相当于指定地址为InetAddress。getByName (null)。也就是说,它相当于指定loopback接口的地址。

3.布局

<?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"    xmlns:app="http://schemas.android.com/apk/res-auto"    android:orientation="vertical">    <LinearLayout        android:id="@+id/lay_server"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:orientation="vertical">        <TextView            android:id="@+id/tv_ip_address"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:padding="16dp"            android:text="Ip地址:" />        <Button            android:id="@+id/btn_start_service"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_marginStart="16dp"            android:layout_marginEnd="16dp"            android:text="开启服务"             />        <Button            android:id="@+id/btn_connect_service"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_marginStart="16dp"            android:layout_marginEnd="16dp"            android:text="开启链接"             />        <Button            android:id="@+id/btn_client_send_msg"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_marginStart="16dp"            android:layout_marginEnd="16dp"            android:text="客户端发送消息"            />        <Button            android:id="@+id/btn_server_send_msg"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:layout_marginStart="16dp"            android:layout_marginEnd="16dp"            android:text="服务端发送消息"            />    </LinearLayout></LinearLayout>

4.实现

在activity中

import android.net.wifi.WifiManagerimport android.os.Bundleimport android.util.Logimport androidx.appcompat.app.AppCompatActivityimport com.zyf.vlc.databinding.ActivityMainBindingimport com.zyf.vlc.socket.ClientCallbackimport com.zyf.vlc.socket.ServerCallbackimport com.zyf.vlc.socket.SocketClientimport com.zyf.vlc.socket.SocketServerclass MainActivity : AppCompatActivity(),ServerCallback, ClientCallback {    private  val TAG = "MainActivity"    private lateinit var binding: ActivityMainBinding    //Socket服务是否打开    private var openSocket = false    private var connectSocket = false    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        binding = ActivityMainBinding.inflate(layoutInflater)        setContentView(binding.root)        binding.tvIpAddress.text = "Ip地址:${getIp()}"        //开启服务/关闭服务 服务端处理        binding.btnStartService.setOnClickListener {            openSocket = if (openSocket) {                SocketServer.stopServer();false            } else SocketServer.startServer(this)            //改变按钮文字            binding.btnStartService.text = if (openSocket) "关闭服务" else "开启服务"        }        binding.btnConnectService.setOnClickListener {            val ip = getIp()            connectSocket = if (connectSocket) {                SocketClient.closeConnect();false            } else {                SocketClient.connectServer(ip, this);true            }            binding.btnConnectService.text = if (connectSocket) "关闭连接" else "连接服务"        }        binding.btnClientSendMsg.setOnClickListener {            SocketClient.sendToServer("客户端发送消息")        }        binding.btnServerSendMsg.setOnClickListener {            SocketServer.sendToClient("服务端发送消息")        } private fun getIp() =        intToIp((applicationContext.getSystemService(WIFI_SERVICE) as WifiManager).connectionInfo.ipAddress)    private fun intToIp(ip: Int) =        "${(ip and 0xFF)}.${(ip shr 8 and 0xFF)}.${(ip shr 16 and 0xFF)}.${(ip shr 24 and 0xFF)}"    override fun receiveClientMsg(success: Boolean, msg: String) {        Log.i(TAG, "receiveClientMsg: $msg")    }    override fun receiveServerMsg(msg: String) {        Log.i(TAG, "receiveServerMsg: $msg")    }    override fun otherMsg(msg: String) {        Log.i(TAG, "otherMsg: $msg")    }

最终实现的效果如下

在这里插入图片描述
运行后依次点击按钮,可以得到如下日志
在这里插入图片描述


参考

Android Socket通讯

总结

本文简单介绍了Android 中Socket 的使用方法,并通过简单的示例帮助理解。
可以关注下我的公众号,我会不定时分享文章和帮助解决问题

来源地址:https://blog.csdn.net/shop_and_sleep/article/details/131937105

--结束END--

本文标题: Android Socket 简单介绍

本文链接: https://www.lsjlt.com/news/416571.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Android Socket 简单介绍
    文章目录 前言一、Socket是什么?百度百科的解释我自己的理解 二、简单示例1.服务端2.客户端3.布局4.实现 参考总结 前言 最近需求需要使用Socket进行通讯,我在工作...
    99+
    2023-09-23
    android
  • Android init.rc文件简单介绍
    Android init.rc文件简单介绍 init.rc脚本是由Android中linux的第一个用户级进程init进行解析的。 init.rc 文件并不是普通的配置文件,而...
    99+
    2022-06-06
    init Android
  • Android中的Adapter简单介绍
    Android中的Adapter在自定义显示列表时非常有用,比如SimpleAdapter,它的构造函数是:  public SimpleAdapter (Context co...
    99+
    2022-06-06
    adapter Android
  • Android Framework Application Framework层简单介绍
    引言               Andro...
    99+
    2022-06-06
    framework Android
  • Android Accessibility 辅助功能简单介绍
    Android Accessibility 辅助功能 Accessibility: 许多Android使用者因为各种情况导致他们要以不同的方式与手机交互。 这包括了有些用户...
    99+
    2022-06-06
    Android
  • Android popupwindow简单使用方法介绍
    先看下效果 1.首页 package com.yskj.jh.demopopupwindow; import android.content.Context; impo...
    99+
    2022-06-06
    方法 popupwindow Android
  • Android Retrofit的简单介绍和使用
    Retrofit与okhttp共同出自于Square公司,retrofit就是对okhttp做了一层封装。把网络请求都交给给了Okhttp,我们只需要通过简单的配置就能使用re...
    99+
    2022-06-06
    retrofit Android
  • Android中dumpsys命令用法简单介绍
    在Android手机上, 通过使用adb shell命令可以进入android系统的shell, 该shell除支持一些常用的标准命令之外,还支持一些和android系统相关的...
    99+
    2022-06-06
    Android
  • Django admin简单介绍
    生成同步数据库的脚本: python manage.py makemigrations 同步数据库: python manage.py migrate 创建后台用户 python manage.py createsuperuser 访...
    99+
    2023-01-31
    简单 Django admin
  • Django ajax 简单介绍
    AJAX Asynchronous Javascript And XML是 "异步Javascript和XML"。即使用 Javascript 语言与服务器进行异步交互,传输的数据为XML。 同步交互:客户端发出一个请求后,需要等待服务器...
    99+
    2023-01-31
    简单 Django ajax
  • C++ OpenMP简单介绍
    目录一、背景知识1、program作用2、C++不同版本区别二、什么是OpenMP三、关键字1、reduction 作用2、default(shared)作用一、背景知识 1、pro...
    99+
    2023-05-20
    c++ OpenMP简介 c++ OpenMP
  • 4:GTID简单介绍
    概述: 当使用GTIDs时,可以识别和跟踪每一个事务,因为它是在原始服务器上提交的,并由任何slave应用;简单来说就是master提交的所有事务都在slaves应用一次,两者的数据就能保证一致性,此外,...
    99+
    2022-10-18
  • oracle lob 简单介绍
    何为LOB?lob为oracle数据库的一个大对象数据类型,可以存储超过4000bytes的字符串,二进制数据,OS文件等大对象信息.最大可存储的容量根oracle的版本和oracle 块大小有关.有那几种...
    99+
    2022-10-18
  • 1.AutoMapper简单介绍
    官网:http://automapper.org/ 源码:https://github.com/AutoMapper/AutoMapper NUGET安装: PM> Install-Package AutoMapper Au...
    99+
    2020-08-26
    1.AutoMapper简单介绍
  • 201_DMA-BUF简单介绍
    一、DMA-BUF等概念的介绍 首先需要明确DMA-BUF,Dma buffer,ION和DMA-BUF Heap是不同的概念。 在Android 多媒体系统中为了减少因不同进程之间内存的多次拷贝而产生的不必要的开销,最直接的想法是希望跟硬...
    99+
    2023-08-16
    linux android java 缓存
  • 免杀简单介绍
    免杀简单介绍 免杀是什么? ​ 免杀,指的是一种能使病毒木马免于被杀毒软件查杀的技术。 为什么要制作免杀? ​ 当前不论是个人PC还是服务器都有杀软,如个人PCwindows操作系统自带的 W...
    99+
    2023-09-01
    服务器 php 运维
  • Android学习之介绍Binder的简单使用
    前言 最近因为公司项目需求,需要远程调度启动客户端输入法输入内容。 这就是大致的需求流程,这篇首先讲远程与服务控制端通讯。首先控制服务端定义好一个Service,且在Ser...
    99+
    2022-06-06
    android学习 binder Android
  • python元组简单介绍
    目录1、拆包2、enumerate3、list()元组的特点:是一种不可变序列,一旦创建就不能修改 1、拆包 将元组的元素取出赋值给不同变量 >>> a = ...
    99+
    2022-11-12
  • Java单例模式简单介绍
    一、概念单例模式是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例类的特殊类。通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源。如果希望在系统中某个类的对象只能存在一个,...
    99+
    2023-05-31
    java 单例模式 ava
  • Android中socket通信简单实现
    Android中socket通信简单实现 socket通信需要有一个服务器和客户端,可以把同一个APP作为服务器跟客户端,也可以分开成两个APP...
    99+
    2022-06-06
    socket通信 socket Android
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作