Android网络编程之TCP/UDP学习

Android网络编程之TCP/UDP学习


本文部分资料来源于网络,仅作为学习纪录用途。

Andorid网络编程简介:

通过网络实现客户端服务端数据的共享访问

网络通讯模型

开放系统互连参考模型:

  • 应用层:通讯的应用程序(类似快递客户端)
  • 表示层:数据的表示格式(类似快递的种类)
  • 会话层:开始、控制和结束一个会话(类似快递点接揽业务)
  • 传输层:网络传输的通讯规则(类似快递运输的方式和规则)
  • 网络层:识别目标机器的IP地址(类似快递投放的目标地点)
  • 数据链路层:单个链路传输数据规则,主要由运营商来定义。(类似快递公司对于具体城市定义的规则)
  • 物理层:传输介质的特性标准(类似快递运输的过程)

TCP/IP 模型 4 层:

  • 应用层
  • 传输层
  • 网络层
  • 主机至网络层

image_1c90ct42t3l326e84b16va79.png-87.6kB

一个应用层应用一般都会使用到两个传输层协议之一:
面向连接的 TCP 传输控制协议和面向无连接的 UDP 用户数据报协议。

下面分析 TCP/IP 协议栈中常用的 IP、 TCP 和 UDP 协议。

  • TPC面向连接,具有可靠性,流控制,错误恢复等特性。
  • UDP面向无连接,比较简单,UDP头包含字节较少,所以比TCP负载消耗少。

UDP 用来支持那些需要在计算机之间传输数据的网络应用,包括网络视频会议系统在内的众多的客户端 / 服务器模式的网络应用都需要使用UDP协议。 UDP 协议的主要作用是将网络数据流量压缩成数据报的形式。

网络三要素

  • IP地址:32位二进制,划分为4段,每段范围0-255,采用十进制表示。

    1. A类IP地址
    一个A类IP地址由1字节的网络地址和3字节主机地址组成,网络地址的最高位必须是“0”, 地址范围从1.0.0.0 到126.0.0.0。可用的A类网络有126个,每个网络能容纳1亿多个主机。

    2. B类IP地址
    一个B类IP地址由2个字节的网络地址和2个字节的主机地址组成,网络地址的最高位必须是“10”,地址范围从128.0.0.0到191.255.255.255。可用的B类网络有16382个,每个网络能容纳6万多个主机 。

    3. C类IP地址
    一个C类IP地址由3字节的网络地址和1字节的主机地址组成,网络地址的最高位必须是“110”。范围从192.0.0.0到223.255.255.255。C类网络可达209万余个,每个网络能容纳254个主机。

    4. D,E类IP地址不常用,另外127.0.0.1是本机回环地址。

  • 端口号

    1. 用于标识进程的逻辑地址,不同进程的标识
    2. 有效端口:0~65535,其中0-1024系统使用或保留端口
    3. 一般说的都是软件意义上的端口
    4. IP地址类似于门牌号,端口类似于房间号
  • 传输协议

    1. TCP
      TCP(Transmission Control Protocol 传输控制协议
      面向连接,基于字节流的传输层通信协议。
      位于IP协议之上,可靠的端对端协议
      重发技术,保证数据内容准确
      大数据量传输
      三次握手完成连接,属于可选协议
      必须建立连接,效率稍低
      类似于打电话

    2. UDP
      用户数据报协议
      无连接,速度快,不可靠的传输层协议
      位于IP协议之上,即UDP数据报(64K内)是封装在IP数据包中进行传输
      类似于发快递,发短信,常用于网络视频会议等情景

    3. IP
      TCP/IP协议模型中关键部分,Internet中所有数据包都通过IP包的方式进行传输。
      能够适应不同的网络硬件。
      无连接
      不可靠

InetAddress.java

* @see     java.net.InetAddress#getByAddress(byte[])
* @see     java.net.InetAddress#getByAddress(java.lang.String, byte[])
* @see     java.net.InetAddress#getAllByName(java.lang.String)
* @see     java.net.InetAddress#getByName(java.lang.String)
* @see     java.net.InetAddress#getLocalHost()

Socket对象

  • 套接字,为网络服务提供的一种机制
  • 通信两端都是Socket
  • 应用程序通过Socket向网络发送请求或响应网络请求
  • 位于会话层

TCP工作流程

TCP 服务器端工作的主要步骤如下。
步骤 1 调用 ServerSocket( int port) 创建一个 ServerSocket, 并绑定到指定端口上。
步骤 2 调用 accept(), 监听连接请求, 如果客户端请求连接, 则接受连接,返回通信套接字。
步 骤 3  调 用 Socket 类 的 getOutputStream() 和 getInputStream() 获 取 输 出 和 输 入 流,
开始网络数据的发送和接收。
步骤 4 关闭通信套接字。

示例代码如下所示:

public class TcpReceiveDemo {
    public static void main(String[] argv) throws IOException {
        // 1. 创建serverSocket服务器端对象 监听具体的端口
        ServerSocket ss = new ServerSocket(10002);
        // 2. 获取具体的连接客户端对象
        Socket s = ss.accept(); // 阻塞式
        String ip = s.getInetAddress().getHostAddress();
        System.out.println(ip + "--------connected---------");

        // 3. 通过客户端对象获取读取流对象,读取客户端发送的消息
        InputStream in = s.getInputStream();
        byte[] buff = new byte[1024];
        int len = in.read(buff);
        String str = new String(buff, 0, len);
        System.out.println("Client: " + str);

        // 4. 获取socket对象,将数据写入客户端
        OutputStream out = s.getOutputStream();
        out.write("已收到".getBytes());

        // 5. 关闭流对象
        s.close();
        ss.close();
    }
}

TCP 客户端工作的主要步骤如下。
步骤 1 调用 Socket() 创建一个流套接字, 并连接到服务器端。
步骤 2 调用 Socket 类的 getOutputStream() 和 getInputStream() 方法获取输出和输入
流, 开始网络数据的发送和接收。
步骤 3 关闭通信套接字。

编写 TCP 客户端代码如下所示:

public class TcpSendDemo {
    public static void main(String[] argv) throws IOException {
        // 1. 创建客户端socket服务 指定目标地址及端口
        Socket s = new Socket("192.168.0.103", 10002);
        // 2. 通过socket对象向服务器写入数据
        OutputStream out = s.getOutputStream();
        out.write("Hello,服务器!!".getBytes());
        // 2.1 通过socket对象获取服务器返回的数据
        InputStream in = s.getInputStream();
        byte[] buff = new byte[1024];
        int len = in.read(buff);
        String str = new String(buff, 0, len);
        System.out.println("server: " + str);
        // 3. 关闭资源
        s.close();
    }
}

测试流程同下面的UDP
image_1c90mgd5e1j3o8kfati1gjc7jd9.png-135.6kB

UDP工作流程

UDP 服务器端工作的主要步骤如下。
步骤 1 调用 DatagramSocket(int port) 创建一个数据报套接字, 并绑定到指定端口上。
步骤 2 调用 DatagramPacket( byte[]buf,int length), 建立一个字节数组以接收 UDP 包。
步骤 3 调用 DatagramSocket 类的 receive(), 接受 UDP 包。
步骤 4 关闭数据报套接字。

public class UdpReceiveDemo {
    public static void main(String[] argv) throws IOException {
        // 建立udp socket服务
        DatagramSocket socket = new DatagramSocket(9527);
        while(true){
            byte[] buff = new byte[1024];
            // 准备用于存储发送数据的数据包
            DatagramPacket dp = new DatagramPacket(buff, buff.length);
            // 阻塞式的接收方法
            socket.receive(dp);
            String ip = dp.getAddress().getHostAddress();
            String text = new String(dp.getData(), 0, dp.getLength());
            System.out.println("ip:" + ip + "; 发送内容:" + text + "; 端口:" + dp.getPort());
        }
        // 由于这里一直在等待接收数据包,所以没有关闭资源
        // socket.close();
    }
}

UDP 客户端工作的主要步骤如下。
步骤 1 调用 DatagramSocket() 创建一个数据包套接字。
步骤 2 调用 DatagramPacket( byte[]buf,int offset,int length,InetAddress address,int port),
建立要发送的 UDP 包。
步骤 3 调用 DatagramSocket 类的 send() 发送 UDP 包。
步骤 4 关闭数据报套接字。

public class UdpSendDemo {
    public static void main(String[] argv) throws IOException {
        // 建立udp socket服务
        DatagramSocket socket = new DatagramSocket(8888);

        // 准备需要发送的数据
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while ((line = br.readLine()) != null) {
            byte[] buff = line.getBytes(); // 数据转换成字节数组
            // 将需要发送的数据封装成数据包
            DatagramPacket dp = new DatagramPacket(buff, buff.length, InetAddress.getByName("192.168.0.103"),9527);
            // 调用send方法将数据包发送
            socket.send(dp);
            if ("886".equals(line)) {
                break;
            }
        }

        // 关闭资源
        socket.close();
    }
}
  • 发送端端口8888和接收端端口9527都是自定义的
  • 192.168.0.103是接收端的地址,由于在本地主机上做实验,所以用的是本机IP
  • BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) 将标准输入流转换成BufferedReader。

联合测试查看实验现象:
1. 将发送和接收端两个java文件单独拷贝出来,并去掉文件中的包名
2. 使用javac分别编译,并在两个终端中使用java运行。
3. 在运行发送端程序的终端输入字符,并在运行接收端程序的终端进行查看
实验现象:
image_1c90kpjp716o6o496s41a71dgj9.png-91.8kB

项目源码地址

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值