53. 【Android教程】Socket 网络接口

Socket 网络接口

大家在学习计算机网络的时候一定学习过 TCP/IP 协议以及最经典的 OSI 七层结构,简单的回忆一下这 7 层结构:
从下到上依次是:

  • 物理层
  • 数据链路层
  • 互联层
  • 网络层
  • 会话层
  • 表示层
  • 应用层

TCP/IP 协议对这 7 层了做一点精简,变为了 4 层结构:

我们现在的网路通信模型基本上都是按照这个层级来分发的,当然也包括了 Android 中的网络模型,简单回顾一下基础之后,开始学习今天的网络接口——Socket。

1. TCP 与 UDP

在模型之下,又衍生出两种经典的传输层协议——TCP 和 UDP,我们分别看看这两个协议。

1.1 TCP 协议

TCP 协议是传输控制协议是一个面向连接的协议,所谓的面向连接表示的是通信双方在传输数据之前,需要搭建一个专用的通信线路,并且在结束的时候需要将其关闭。在有了这条专用线路作保障之后,就能准确无误的将数据传递给对方,所以 TCP 是一种可靠的通信方式,它能够准确知道对方是否成功接收了消息。

1.2 UDP 协议

UDP 又叫用户数据包协议,相对于 TCP,它是一种面向无连接的协议,也就是通信双方在交换数据之前无需建立一条专用通道,当然在通信结束前也无需释放通道。这样一来,通信的效率非常高,但缺点是我们无法确定发出去的消息对方是否能够准确收到,所以它是一个轻量不可靠的通信方式。

以上的定义描述了二者主要的差异,更多细致的内容可以参考其他资料。

2. Socket 的基础概念

Socket 翻译成中文是“套接字”,它是应用层和传输层中间的一个抽象中间件,它封装了底层的 TCP / IP 协议族,并向上暴露 API 给应用层,从而向上屏蔽底层协议细节。 所以 Socket 可以作为底层网络门面来让我们不在拘泥于复杂的底层传输协议,而将更多的重心放在自己的功能开发上。 下图是 Socket 的一个整体工作原理:

每个 Socket 对象都对应着一个 IP 地址和一个端口号,用来标识互联网上的唯一目的地址,然后就可以通过 TCP 或者 UDP 将数据发送给对方。

3. Socket 的工作流程

首先看看 Socket 的工作流程图:

3.1 Server 监听端口

首先由服务端初始化 Socket 接口,然后绑定并监听自己的端口号,此时服务端会阻塞式等待客户端连接。

3.2 Client 连接端口

客户端可以在需要发送消息的时候初始化 Socket 接口,设置服务端的 IP 地址和端口号就可以连接到服务器,接着在连接成功之后,双方就完成了连接的建立。

3.3 数据传递和连接断开

在连接建立好之后,客户端或者服务端双方就可以开始发送数据了,在数据传输完毕之后,双方任一方都可以申请断开连接,此后通道关闭,数据传输完成。

4. Socket 的基本用法

  1. 首先创建一个 ServerSocket 对象
public ServerSocket(int port) throws IOException

创建 Socket 服务只需要传入一个端口号即可。

  1. 阻塞监听端口
public Socket accept() throws IOException

通过调用accept()方法,server 便会阻塞式的监听第 1 步设置的端口号,等待客户端连接。

  1. 客户度创建 Socket 对象
public Socket(String host, int port)  throws UnknownHostException, IOException

和前面说的一样,创建 Socket 需要两个必要的参数:

  • **host:**服务端的网络地址
  • **port:**服务端开放的对应端口号
  1. 获取输入输出流
socket.getInputStream();
socket.getOutputStream();

服务端和客户端通过这两个方法分别拿到输入输出流,从而向流里面写消息或者从流里面读数据完成数据的发送和接收。

  1. 断开连接
    在数据传输完毕之后,通过close()方法断开连接,完成本次通信。

5. Socket 网络通信示例

本节在电脑上通过 Java 搭建一个 Socket Server,然后手机作为 Client 来连接 Server。这个需要保证手机和电脑在同一个 Wifi 网段下。

5.1 搭建 Server

大家在学习 Android 之前,应该都有学过纯 Java 程序,可以通过javac命令来将 java 代码编译成字节码,然后通过java命令运行,当然也可以在 Android Studio 里面直接运行带main()方法的 Java 程序。
首先在工程里新建一个 Java Library,注意不是 Android Library。

然后创建一个带main()函数的类,在里面完成 Socket 的创建和初始化:

package com.emercy.libsocket;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;public class SocketServer {public static void main(String[] args) throws IOException {// 1. Create ServerSocketServerSocket serverSocket = new ServerSocket(8888);// 2. monitoringSystem.out.println("server start listen : " + getIpAddress());Socket socket = serverSocket.accept();System.out.println("accept");// 3. input streamInputStream is = socket.getInputStream();InputStreamReader reader = new InputStreamReader(is);BufferedReader br = new BufferedReader(reader);String content;StringBuffer sb = new StringBuffer();while ((content = br.readLine()) != null) {sb.append(content);}System.out.println("server receiver: " + sb.toString());socket.shutdownInput();br.close();reader.close();is.close();socket.close();serverSocket.close();System.out.println("server receiver: ");}public static String getIpAddress() {try {Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();InetAddress ip = null;while (allNetInterfaces.hasMoreElements()) {NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {continue;} else {Enumeration<InetAddress> addresses = netInterface.getInetAddresses();while (addresses.hasMoreElements()) {ip = addresses.nextElement();if (ip instanceof Inet4Address) {return ip.getHostAddress();}}}}} catch (Exception e) {System.err.println("IP地址获取失败" + e.toString());}return "";}
}

运行之后,开始等待连接并打印当前设备的 IP 地址,这里要特别注意,有些教程里面会用InetAddress.getLocalHost()这种方式获取 IP 返回“127.0.0.1”,这个是 local host,在跨设备通信中无法使用。

5.2 Client 连接

接下来编写 Android 程序,xml 里面只放置一个 Button 用于触发连接,这里就不列出来了。点击 button 之后按照上面的步骤来依次创建 Socket,设置 IP 和 port,接着获取输入输出流即可。
**注意:**网络请求属于耗时操作, Android 要求网络请求必须在子线程中执行,所以我们需要在onClick()中 new 一个 thread。


package com.emercy.myapplication;import android.app.Activity;
import android.os.Bundle;
import android.view.View;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {//1. Create Clientsuper.onCreate(savedInstanceState);setContentView(R.layout.activity_main);findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {new Thread(new Runnable() {@Overridepublic void run() {Socket socket;try {//1. create socketsocket = new Socket("10.64.210.51", 12345);//2. output streamOutputStream os = socket.getOutputStream();//3. Send dataos.write("Hello world".getBytes());System.out.println("send message");os.flush();socket.shutdownOutput();os.close();socket.close();} catch (IOException e) {e.printStackTrace();}}}).start();}});}
}

首先运行 Server,接着打开 App,点击“连接”Button 就可以和 Server 通信了。

6. 小结

本节学习了一个底层的网络接口——Socket,它内部实现了计算机网络中最基础的协议和模型,可以让我们不再关心那些繁琐复杂的协议规则,从而轻松的将数据传输出去。首先给大家回顾了 IOS 和 TCP / IP 的几层模型,然后工作在传输层的两个重要通信协议 TCP / UDP,接着按照步骤来分别创建 SocketServer 和 Socket,通过 InputStream 和 OutputStream 进行通信。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/7321.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

三岁孩童被家养大型犬咬伤 额部撕脱伤达10公分

近期&#xff0c;一名被家养大型犬咬伤了面部的3岁小朋友&#xff0c;在被家人紧急送来西安国际医学中心医院&#xff0c;通过24小时急诊门诊简单救治后&#xff0c;转至整形外科&#xff0c;由主治医师李世龙为他实施了清创及缝合手术。 “患者额部撕脱伤面积约为10公分&…

Python3中Richdem包遇到问题

Python3中Richdem包遇到问题 文章目录 Python3中Richdem包遇到问题问题一报错解决 问题二报错解决 参考 问题一 报错 RichDEM 是一套数字高程模型 &#xff08;DEM&#xff09; 水文分析工具&#xff0c;这次打算用richdem进行地形分析&#xff0c;尝试在conda里面安装richde…

【华为】NAT的分类和实验配置

【华为】NAT的分类和实验配置 NAT产生的技术背景IP地址分类NAT技术原理NAT分类静态NAT动态NATNAPTEasy IP&#xff08;PAT&#xff09;NAT Server 配置拓扑静态NAT测试抓包 动态NAT测试抓包 NAPT测试抓包 PAT测试抓包 NAT Server检测抓包 PC1PC2服务器 NAT产生的技术背景 随着…

【管理篇】管理三步曲:团队建设(二)

目录标题 如何着手团队建设提升个人能力1、要提升员工的什么能力2、提升员工个人能力的初衷是什么&#xff1f;3、如何达成上述目标4、应该如何激发员工学习的动力和意愿呢5、关于提升员工的能力&#xff0c;有两个信念特别重要&#xff1a; 提升员工的工作意愿和积极性1、管理…

Spring与AI结合-spring boot3整合AI组件

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 目录 写在前面 spring ai简介 单独整合al接口 整合Spring AI组件 起步条件 ​编辑 进行必要配置 写在最后 写在前面 本文介绍了springboot开发后端服务中&#xff0c;AI组件(Spring A…

软件工程案例学习-图书管理系统-面向对象方法

文档编号&#xff1a;LMS_1 版 本 号&#xff1a;V1.0 ** ** ** ** ** ** 文档名称&#xff1a;需求分析规格说明书 项目名称&#xff1a;图书管理系统 项目负责人&#xff1a;计敏 胡杰 ** ** …

使用Docker安装MySql数据库

大家好&#xff0c;今天给大家分享一下如何使用docker安装MySql数据库&#xff0c;关于docker的安装和常用命令&#xff0c;大家可以参考下面两篇文章&#xff0c;本文中不做过多描述。 Docker在Windows与CentOS上的安装 Docker常用命令 一、拉取MySql数据库镜像 docker pul…

IIS部署vue项目 IIS重写URL

【第一步】安装IIS {1&#xff09;打开控制面板 -> 打开程序和功能 -> 打开启用或关闭windows功能 &#xff08;2&#xff09;找到 Internet Information Services 勾选【web管理工具】和【万维网服务】&#xff0c;然后 确定 【第二步】安装URL重写模块 1). 安装URL …

C++ | Leetcode C++题解之第73题矩阵置零

题目&#xff1a; 题解&#xff1a; class Solution { public:void setZeroes(vector<vector<int>>& matrix) {int m matrix.size();int n matrix[0].size();int flag_col0 false;for (int i 0; i < m; i) {if (!matrix[i][0]) {flag_col0 true;}for …

【笔试训练】day20

1.经此一役小红所向无敌 默认小红血量无限。直接计算出经过几轮攻击后&#xff0c;会出现人员伤亡。 对于对立来说他最多承受n轮光的攻击&#xff0c;对于光来说&#xff0c;他最多承受立得m轮攻击。 所以在经过min(n,m)轮回合之后&#xff0c;他们两个人至少死一个。活下来的…

html实现网页插入音频

前言 欢迎来到我的博客 个人主页:北岭敲键盘的荒漠猫-CSDN博客 本文主要介绍html中 如何插入音乐和视频 视频插入 标签:<video></video> 兼容格式:mp4,因为别的浏览器都有不兼容的格式&#xff0c;唯一对mp4全都兼容。所以尽量使用mp4格式。 属性: 属性属性值…

解决Win10家庭版找不到组策略gpedit.msc的·方法

因为电脑出问题&#xff0c;一开机就会自动开启ie浏览器&#xff0c;所以就想找有没有方法解决&#xff0c;然后就了解到了gpedit.msc的作用以及相关的一些方法&#xff0c;也是为之后也许有人遇到相同的问题有个提供方法的途径。 首先我们直接运行gpedit.msc 是找不到的&…

【Qt QML】QLibrary加载共享库中的类

QLibrary是一个用于加载动态链接库&#xff08;或称为共享库&#xff09;的类。它提供了一种独立于平台的方式来访问库中的功能。 在QLibrary中&#xff0c;可以通过构造函数或setFileName()方法设置要加载的库文件名。当加载库文件时&#xff0c;QLibrary会搜索所有平台特定的…

计算机网络【应用层】邮件和DNS

文章目录 电子邮件DNSDNS提供的服务&#xff1a;域名分级域名解析流程DNS资源记录DNS服务器类型 电子邮件 使用SMTP协议发送邮件之前&#xff0c;需要将二进制多媒体数据编码为ASCII码SMTP一般不使用中间邮件服务器发送邮件&#xff0c;如果收件服务器没开机&#xff0c;那么会…

【iOS】多线程

文章目录 前言一、多线程的选择方案二、GCD和NSOperation的比较二、多线程相关概念任务队列 三、死锁情况主队列加同步任务 四、任务队列组合主队列异步并发队列异步 前言 这两天将iOS的多线程的使用都看了一遍&#xff0c;iOS的多线程方案有许多&#xff0c;本篇博客主要总结…

流畅的python-学习笔记_符合python风格的对象

对象表示形式 查看对象说明&#xff0c;可以通过__repr__和__str__方法&#xff0c;前者主要用于开发者&#xff0c;后者主要用于用户&#xff0c;这两个方法分别对内置函数repr和str函数提供支持 向量类 备选构造方法 classmethod和staticmethod staticmethod用的不是特别…

基于鸢尾花数据集的四种聚类算法(kmeans,层次聚类,DBSCAN,FCM)和学习向量量化对比

基于鸢尾花数据集的四种聚类算法&#xff08;kmeans&#xff0c;层次聚类&#xff0c;DBSCAN,FCM&#xff09;和学习向量量化对比 注&#xff1a;下面的代码可能需要做一点参数调整&#xff0c;才得到所有我的运行结果。 kmeans算法&#xff1a; import matplotlib.pyplot a…

音视频开发3 视频基础,图片基础

图片像素&#xff08;Pixel&#xff09; 一张图片是由多少个 像素 构成的。 例如一张图片是由60x50组成的。 位深度 bit depth RGB表示法 红&#xff08;Red&#xff09;、绿&#xff08;Green&#xff09;、蓝&#xff08;Blue&#xff09; 除了24bit&#xff0c;常见的位深…

electron 通信总结

默认开启上下文隔离的情况下 渲染进程调用主进程方法&#xff1a; 主进程 在 main.js 中&#xff0c; 使用 ipcMain.handle&#xff0c;添加要处理的主进程方法 const { ipcMain } require("electron"); 在 electron 中创建 preload.ts 文件&#xff0c;从 ele…

在Linux上使用Selenium驱动Chrome浏览器无头模式

大家好&#xff0c;我们平时在做UI自动化测试的时候&#xff0c;经常会用到Chrome浏览器的无头模式&#xff08;无界面模式&#xff09;&#xff0c;并且将测试代码部署到Linux系统中执行&#xff0c;或者平时我们写个爬虫爬取网站的数据也会使用到&#xff0c;接下来和大家分享…