Android通过Socket实现TCP、UDP通信

参考:

《深入理解Android网络编程》

https://www.jianshu.com/p/089fb79e308b

一、TCP,UDP基本介绍

1. TCP

传输控制协议(Transmission Control Protocol,TCP)是一种面向连接的、可靠的、基于字节流的传输层通信协议。TCP的可靠体现在它的三次握手和四次挥手上,不熟悉的可以参考下我的另外一篇文章,HTTP请求流程

2. UDP

用户数据报协议(UDP)是 TCP/IP 模型中一种面向无连接的传输层协议,提供面向事 务的简单不可靠信息传送服务。UDP 协议基本上是IP 协议与上层协议的接口。UDP 协议 适用于端口分别运行在同一台设备上的多个应用程序中。

与 TCP 不同,UDP 并不提供对IP 协议的可靠机制、流控制以及错误恢复功能等,在 数据传输之前不需要建立连接。由于 UDP 比较简单,UDP 头包含很少的字节,所以比 TCP 负载消耗少。 

二、Socket

实现TCP和UDP的过程是一项繁杂的工作,需要大量可靠的代码来完成。为了使程序员不必费心于上述这些底层具体细节,人们通过Socket对网络纠错、包大小、包重传等进行了封装。Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。

  1. Socket不是一种协议,而是一个编程调用接口(API),属于传输层(主要解决数据如何在网络中传输)
  2. 即:通过Socket,我们才能在Andorid平台上通过 TCP/IP协议进行开发
  3. 对用户来说,只需调用Socket去组织数据,以符合指定的协议,即可通信

服务端要和客户端通信,两者都要实例化一个Socket,接下来介绍关于TCP和UDP的不同实现。

1. 使用TCP通信

TCP 建立连接之后,通信双方都同时可以进行数据的传输 ;在保证可靠性上,采用超 时重传和捎带确认机制 ;在流量控制上,采用滑动窗口协议,协议中规定,对于窗口内未 经确认的分组需要重传;在拥塞控制上,采用慢启动算法。TCP 通信的原理示意图如下图所示。

TCP 服务器端工作的主要步骤如下。

  • 调用 ServerSocket(int port)创建一个 ServerSocket,并绑定到指定端口上。
  • 调用accept(),监听连接请求,如果客户端请求连接,则接受连接,返回通信 套接字。
  • 调用Socket 类的getOutputStream() 和 getInputStream() 获取输出和输入流, 开始网络数据的发送和接收。
  • 关闭通信套接字。 

主要代码如下:

ServerSocket server = null;
// 1、创建ServerSocket服务器套接字
server = new ServerSocket(port);
// 设置连接超时时间,不设置,则是一直阻塞等待
// server.setSoTimeout(8000);

// 2、等待被连接。在连接超时时间内连接有效,超时则抛异常,
Socket client = server.accept();
System.out.println("connected... ");
// 设置读取流的超时时间,不设置,则是一直阻塞读取
// client.setSoTimeout(5000);

// 3、获取输入流和输出流
InputStream inputStream = client.getInputStream();
OutputStream outputStream = client.getOutputStream();

// 4、读取数据
byte[] buf = new byte[1024];
int len = inputStream.read(buf);
String receData = new String(buf, 0, len, Charset.forName("UTF-8"));
System.out.println("received data from client: " + receData);

// 5、发送响应数据
byte[] responseBuf = "Hi, I am Server".getBytes(Charset.forName("UTF-8"));
outputStream.write(responseBuf, 0, responseBuf.length);

TCP 客户端工作的主要步骤如下。

  • 调用 Socket() 创建一个流套接字,并连接到服务器端。 
  • 调用Socket 类的getOutputStream() 和 getInputStream() 方法获取输出和输入 流,开始网络数据的发送和接收。 
  • 关闭通信套接字。 

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

Socket socket = null;
try {
    // 1、创建连接
    socket = new Socket(host, port);
    if (socket.isConnected()) {
        Log.i(TAG, "connect to Server success");
    }

    // 2、设置读流的超时时间
    socket.setSoTimeout(8000);

    // 3、获取输出流与输入流
    OutputStream outputStream = socket.getOutputStream();
    InputStream inputStream = socket.getInputStream();

    // 4、发送信息
    byte[] sendData = "Hello, I am client".getBytes(Charset.forName("UTF-8"));
    outputStream.write(sendData, 0, sendData.length);
    outputStream.flush();

    // 5、接收信息
    byte[] buf = new byte[1024];
    int len = inputStream.read(buf);
    String receData = new String(buf, 0, len, Charset.forName("UTF-8"));
    Log.i(TAG, receData);

} catch (IOException e) {
    e.printStackTrace();
    Log.i(TAG, "error: " + e.toString());
} finally {
    if (socket != null) {
    try {
        socket.close();
        socket = null;
    } catch (IOException e) {
        e.printStackTrace();
    }
  }
}

注意:

  1. 安卓客户端需要加上INTERNET的权限
  2. Socket的操作需要放到子线程中进行

运行结果如下:

2. 使用UDP通信

UDP 有不提供数据报分组、组装和不能对数据包排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP 用来支持那些需要在计算机之间传输数据 的网络应用,包括网络视频会议系统在内的众多的客户端/ 服务器模式的网络应用都需要使 用 UDP 协议。UDP 协议的主要作用是将网络数据流量压缩成数据报的形式。一个典型的数 据报就是一个二进制数据的传输单位。UDP 传输原理示意图如下所示。

UDP 服务器端工作的主要步骤如下。 

  • 调用 DatagramSocket(int port) 创建一个数据报套接字,并绑定到指定端口上。 
  • 调用 DatagramPacket(byte[]buf,int length), 建立一个字节数组以接收 UDP 包。 
  • 调用 DatagramSocket 类的 receive(),接受 UDP 包。 
  • 关闭数据报套接字。 

示例代码如下所示:

byte[] lMsg = new byte[1024];
DatagramPacket dp = new DatagramPacket(lMsg, lMsg.length);
DatagramSocket ds = null;
try {
    ds = new DatagramSocket(8990);
    ds.receive(dp);
} catch (SocketException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    if (ds != null) {
        ds.close();
    }
  }
if (dp.getData() != null){
    String str = new String(dp.getData(), Charset.forName("UTF-8"));
    System.out.println("received data from client: " + str);
}

UDP 客户端工作的主要步骤如下。 

  • 调用 DatagramSocket() 创建一个数据包套接字。 
  • 调用DatagramPacket(byte[]buf,int offset,int length,InetAddress address,int port), 建立要发送的 UDP 包。 
  • 调用 DatagramSocket 类的 send() 发送 UDP 包。 
  • 关闭数据报套接字。 

示例代码如下所示:

try {
    String udpMsg = "hello UDP";
    DatagramSocket ds = null;
    ds = new DatagramSocket();
    InetAddress serverAddr = InetAddress.getByName("10.8.116.225");
    DatagramPacket dp;
    dp = new DatagramPacket(udpMsg.getBytes(), udpMsg.length(), serverAddr, 8990);
    ds.send(dp);
} catch (SocketException e) {
    e.printStackTrace();
} catch (UnknownHostException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
}

运行结果如下:

三、Socket和HTTP

  • Socket属于传输层,因为 TCP / IP协议属于传输层,解决的是数据如何在网络中传输的问题
  • HTTP协议 属于 应用层,解决的是如何包装数据

两者根本不属于同一层面,所以千万不要混淆了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值