Android网络编程之TCP/UDP学习
本文部分资料来源于网络,仅作为学习纪录用途。
Andorid网络编程简介:
通过网络实现客户端与服务端数据的共享访问
网络通讯模型
开放系统互连参考模型:
- 应用层:通讯的应用程序(类似快递客户端)
- 表示层:数据的表示格式(类似快递的种类)
- 会话层:开始、控制和结束一个会话(类似快递点接揽业务)
- 传输层:网络传输的通讯规则(类似快递运输的方式和规则)
- 网络层:识别目标机器的IP地址(类似快递投放的目标地点)
- 数据链路层:单个链路传输数据规则,主要由运营商来定义。(类似快递公司对于具体城市定义的规则)
- 物理层:传输介质的特性标准(类似快递运输的过程)
TCP/IP 模型 4 层:
一个应用层应用一般都会使用到两个传输层协议之一:
面向连接的 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是本机回环地址。
端口号
- 用于标识进程的逻辑地址,不同进程的标识
- 有效端口:0~65535,其中0-1024系统使用或保留端口
- 一般说的都是软件意义上的端口
- IP地址类似于门牌号,端口类似于房间号
传输协议
TCP
TCP(Transmission Control Protocol 传输控制协议
面向连接,基于字节流的传输层通信协议。
位于IP协议之上,可靠的端对端协议
重发技术,保证数据内容准确
大数据量传输
三次握手完成连接,属于可选协议
必须建立连接,效率稍低
类似于打电话
UDP
用户数据报协议
无连接,速度快,不可靠的传输层协议
位于IP协议之上,即UDP数据报(64K内)是封装在IP数据包中进行传输
类似于发快递,发短信,常用于网络视频会议等情景
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 {ServerSocket ss = new ServerSocket(10002);Socket s = ss.accept(); String ip = s.getInetAddress().getHostAddress();System.out.println(ip + "--------connected---------");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);OutputStream out = s.getOutputStream();out.write("已收到".getBytes());s.close();ss.close();}
}
TCP 客户端工作的主要步骤如下。
步骤 1 调用 Socket() 创建一个流套接字, 并连接到服务器端。
步骤 2 调用 Socket 类的 getOutputStream() 和 getInputStream() 方法获取输出和输入
流, 开始网络数据的发送和接收。
步骤 3 关闭通信套接字。
编写 TCP 客户端代码如下所示:
public class TcpSendDemo {public static void main(String[] argv) throws IOException {Socket s = new Socket("192.168.0.103", 10002);OutputStream out = s.getOutputStream();out.write("Hello,服务器!!".getBytes());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);s.close();}
}
测试流程同下面的UDP
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 {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());}}
}
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 {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);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. 在运行发送端程序的终端输入字符,并在运行接收端程序的终端进行查看
实验现象:
项目源码地址