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

简介: 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. 断开连接
  2. 在数据传输完毕之后,通过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 ServerSocket
        ServerSocket serverSocket = new ServerSocket(8888);
        // 2. monitoring
        System.out.println("server start listen : " + getIpAddress());
 
        Socket socket = serverSocket.accept();
        System.out.println("accept");
 
        // 3. input stream
        InputStream 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 {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //1. Create Client
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Socket socket;
                        try {
                            //1. create socket
                            socket = new Socket("10.64.210.51", 12345);
                            //2. output stream
                            OutputStream os = socket.getOutputStream();
                            //3. Send data
                            os.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 进行通信。


相关文章
安卓手机远程连接登录Windows服务器教程
安卓手机远程连接登录Windows服务器教程
56 4
Python网络编程:从Socket到Web应用
在信息时代,网络编程是软件开发的重要组成部分。Python作为多用途编程语言,提供了从Socket编程到Web应用开发的强大支持。本文将从基础的Socket编程入手,逐步深入到复杂的Web应用开发,涵盖Flask、Django等框架的应用,以及异步Web编程和微服务架构。通过本文,读者将全面了解Python在网络编程领域的应用。
33 1
解决两个 Android 模拟器之间无法网络通信的问题
让同一个 PC 上运行的两个 Android 模拟器之间能相互通信,出(qiong)差(ren)的智慧。
31 3
|
2月前
|
[Java]Socket套接字(网络编程入门)
本文介绍了基于Java Socket实现的一对一和多对多聊天模式。一对一模式通过Server和Client类实现简单的消息收发;多对多模式则通过Server类维护客户端集合,并使用多线程实现实时消息广播。文章旨在帮助读者理解Socket的基本原理和应用。
29 1
Python中的Socket魔法:如何利用socket模块构建强大的网络通信
本文介绍了Python的`socket`模块,讲解了其基本概念、语法和使用方法。通过简单的TCP服务器和客户端示例,展示了如何创建、绑定、监听、接受连接及发送/接收数据。进一步探讨了多用户聊天室的实现,并介绍了非阻塞IO和多路复用技术以提高并发处理能力。最后,讨论了`socket`模块在现代网络编程中的应用及其与其他通信方式的关系。
212 3
Socket通信之网络协议基本原理
【10月更文挑战第10天】网络协议定义了机器间通信的标准格式,确保信息准确无损地传输。主要分为两种模型:OSI七层模型与TCP/IP模型。
网络世界的建筑师:Python Socket编程基础与进阶,构建你的网络帝国!
在数字宇宙中,网络如同复杂脉络连接每个角落,Python Socket编程则是开启这一世界的钥匙。本文将引导你从基础概念入手,逐步掌握Socket编程,并通过实战示例构建TCP/UDP服务器与客户端。你将学会使用Python的socket模块进行网络通信,了解TCP与UDP的区别,并运用多线程与异步IO提升服务器性能。跟随本文指引,成为网络世界的建筑师,构建自己的网络帝国。
39 2
网络编程小白秒变大咖!Python Socket基础与进阶教程,轻松上手无压力!
在网络技术飞速发展的今天,掌握网络编程已成为开发者的重要技能。本文以Python为工具,带你从Socket编程基础逐步深入至进阶领域。首先介绍Socket的概念及TCP/UDP协议,接着演示如何用Python创建、绑定、监听Socket,实现数据收发;最后通过构建简单的聊天服务器,巩固所学知识。让初学者也能迅速上手,成为网络编程高手。
81 1
AI助理

阿里云 AI 助理已上线!

快来体验一下吧。