传智播客——专注于 Java、.Net 和 Php、网页平面设计工程师的培训
第 28 天 网络编程
今日内容介绍
网络通信协议
UDP 通信
TCP 通信
第 1 章 网络通信协议
通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时
需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样。在计算机网络中,
这些连接和通信的规则被称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统
一规定,通信双方必须同时遵守才能完成数据交换。
网络通信协议有很多种,目前应用最广泛的是 TCP/IP 协议(Transmission Control Protocal/Internet
Protoal 传输控制协议/英特网互联协议),它是一个包括 TCP 协议和 IP 协议,UDP(User Datagram
Protocol)协议和其它一些协议的协议组,在学习具体协议之前首先了解一下 TCP/IP 协议组的层次
结构。
在进行数据传输时,要求发送的数据与收到的数据完全一样,这时,就需要在原有的数据上添
加很多信息,以保证数据在传输过程中数据格式完全一致。TCP/IP 协议的层次结构比较简单,共分
为四层,如图所示。
图 1-1 TCP/IP 网络模型
上图中,TCP/IP 协议中的四层分别是应用层、传输层、网络层和链路层,每层分别负责不同的
通信功能,接下来针对这四层进行详细地讲解。
链路层:链路层是用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对
光纤、网线提供的驱动。
网络层:网络层是整个 TCP/IP 协议的核心,它主要用于将传输的数据进行分组,将分组数据发
送到目标计算机或者网络。
传输层:主要使网络程序进行通信,在进行网络通信时,可以采用 TCP 协议,也可以采用 UDP
传智播客——专注于 Java、.Net 和 Php、网页平面设计工程师的培训
协议。
应用层:主要负责应用程序的协议,例如 HTTP 协议、FTP 协议等。
1.1IP 地址和端口号
要想使网络中的计算机能够进行通信,必须为每台计算机指定一个标识号,通过这个标识号来
指定接受数据的计算机或者发送数据的计算机。
在 TCP/IP 协议中,这个标识号就是 IP 地址,它可以唯一标识一台计算机,目前,IP 地址广泛
使 用 的 版 本 是 IPv4 , 它 是 由 4 个 字 节 大 小 的 二 进 制 数 来 表 示 , 如 :
00001010000000000000000000000001。由于二进制形式表示的 IP 地址非常不便记忆和处理,因此通
常会将 IP 地址写成十进制的形式,每个字节用一个十进制数字(0-255)表示,数字间用符号“.”分开,
如 “192.168.1.100”。
随着计算机网络规模的不断扩大,对 IP 地址的需求也越来越多,IPV4 这种用 4 个字节表示的
IP 地址面临枯竭,因此 IPv6 便应运而生了,IPv6 使用 16 个字节表示 IP 地址,它所拥有的地址容
量约是 IPv4 的 8×1028 倍,达到 2128 个(算上全零的),这样就解决了网络地址资源数量不够的问题。
通过 IP 地址可以连接到指定计算机,但如果想访问目标计算机中的某个应用程序,还需要指定
端口号。在计算机中,不同的应用程序是通过端口号区分的。端口号是用两个字节(16 位的二进制
数)表示的,它的取值范围是 0~65535,其中,0~1023 之间的端口号用于一些知名的网络服务和应
用,用户的普通应用程序需要使用 1024 以上的端口号,从而避免端口号被另外一个应用或服务所占
用。
接下来通过一个图例来描述 IP 地址和端口号的作用,如下图所示。
从上图中可以清楚地看到,位于网络中一台计算机可以通过 IP 地址去访问另一台计算机,并通
过端口号访问目标计算机中的某个应用程序。
1.2InetAddress
了解了 IP 地址的作用,我们看学习下 JDK 中提供了一个 InetAdderss 类,该类用于封装一个 IP
地址,并提供了一系列与 IP 地址相关的方法,下表中列出了 InetAddress 类的一些常用方法。
传智播客——专注于 Java、.Net 和 Php、网页平面设计工程师的培训
上图中,列举了 InetAddress 的四个常用方法。其中,前两个方法用于获得该类的实例对象,第
一个方法用于获得表示指定主机的 InetAddress 对象,第二个方法用于获得表示本地的 InetAddress
对象。通过 InetAddress 对象便可获取指定主机名,IP 地址等,接下来通过一个案例来演示 InetAddress
的常用方法,如下所示。
public class Example01 {
public static void main(String[] args) throws Exception {
InetAddress local = InetAddress.getLocalHost();
InetAddress remote = InetAddress.getByName("www.itcast.cn");
System.out.println("本机的 IP 地址:" + local.getHostAddress());
System.out.println("itcast 的 IP 地址:" + remote.getHostAddress());
System.out.println("itcast 的主机名为:" + remote.getHostName());
}
}
第 2 章 UDP 与 TCP 协议
在介绍 TCP/IP 结构时,提到传输层的两个重要的高级协议,分别是 UDP 和 TCP,其中 UDP 是
User Datagram Protocol 的简称,称为用户数据报协议,TCP 是 Transmission Control Protocol 的简称,
称为传输控制协议。
2.1UDP 协议
UDP 是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,
当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同
样接收端在收到数据时,也不会向发送端反馈是否收到数据。
由于使用 UDP 协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输
例如视频会议都使用 UDP 协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生
太大影响。
但是在使用 UDP 协议传送数据时,由于 UDP 的面向无连接性,不能保证数据的完整性,因此
在传输重要数据时不建议使用 UDP 协议。UDP 的交换过程如下图所示。
传智播客——专注于 Java、.Net 和 Php、网页平面设计工程师的培训
2.2TCP 协议
TCP 协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再
传输数据,它提供了两台计算机之间可靠无差错的数据传输。在 TCP 连接中必须要明确客户端与服
务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”。第一次握手,
客户端向服务器端发出连接请求,等待服务器确认,第二次握手,服务器端向客户端回送一个响应,
通知客户端收到了连接请求,第三次握手,客户端再次向服务器端发送确认信息,确认连接。整个
交互过程如下图所示。
由于 TCP 协议的面向连接特性,它可以保证传输数据的安全性,所以是一个被广泛采用的协议,
例如在下载文件时,如果数据接收不完整,将会导致文件数据丢失而不能被打开,因此,下载文件
时必须采用 TCP 协议。
第 3 章 UDP 通信
3.1DatagramPacket
前面介绍了 UDP 是一种面向无连接的协议,因此,在通信时发送端和接收端不用建立连接。
UDP 通信的过程就像是货运公司在两个码头间发送货物一样。在码头发送和接收货物时都需要使用
集装箱来装载货物,UDP 通信也是一样,发送和接收的数据也需要使用“集装箱”进行打包,为此
JDK 中提供了一个 DatagramPacket 类,该类的实例对象就相当于一个集装箱,用于封装 UDP 通信中
发送或者接收的数据。
传智播客——专注于 Java、.Net 和 Php、网页平面设计工程师的培训
想要创建一个 DatagramPacket 对象,首先需要了解一下它的构造方法。在创建发送端和接收端
的 DatagramPacket 对象时,使用的构造方法有所不同,接收端的构造方法只需要接收一个字节数组
来存放接收到的数据,而发送端的构造方法不但要接收存放了发送数据的字节数组,还需要指定发
送端 IP 地址和端口号。
接下来根据 API 文档的内容,对 DatagramPacket 的构造方法进行逐一详细地讲解。
使用该构造方法在创建 DatagramPacket 对象时,指定了封装数据的字节数组和数据的大小,没
有指定 IP 地址和端口号。很明显,这样的对象只能用于接收端,不能用于发送端。因为发送端一定
要明确指出数据的目的地(ip 地址和端口号),而接收端不需要明确知道数据的来源,只需要接收到数
据即可。
使用该构造方法在创建 DatagramPacket 对象时,不仅指定了封装数据的字节数组和数据的大小,
还指定了数据包的目标 IP 地址(addr)和端口号(port)。该对象通常用于发送端,因为在发送数据
时必须指定接收端的 IP 地址和端口号,就好像发送货物的集装箱上面必须标明接收人的地址一样。
上面我们讲解了 DatagramPacket 的构造方法,接下来对 DatagramPacket 类中的常用方法进行详
细地讲解,如下表所示。
3.2DatagramSocket
DatagramPacket 数据包的作用就如同是“集装箱”,可以将发送端或者接收端的数据封装起来。
然而运输货物只有“集装箱”是不够的,还需要有码头。在程序中需要实现通信只有 DatagramPacket
数据包也同样不行,为此 JDK 中提供的一个 DatagramSocket 类。DatagramSocket 类的作用就类似于
码头,使用这个类的实例对象就可以发送和接收 DatagramPacket 数据包,发送数据的过程如下图所
示。
在 创 建 发 送 端 和 接 收 端 的 DatagramSocket 对 象 时 , 使 用 的 构 造 方 法 也 有 所 不 同 , 下 面 对
传智播客——专注于 Java、.Net 和 Php、网页平面设计工程师的培训
DatagramSocket 类中常用的构造方法进行讲解。
该构造方法用于创建发送端的 DatagramSocket 对象,在创建 DatagramSocket 对象时,并没有指
定端口号,此时,系统会分配一个没有被其它网络程序所使用的端口号。
该构造方法既可用于创建接收端的 DatagramSocket 对象,又可以创建发送端的 DatagramSocket
对象,在创建接收端的 DatagramSocket 对象时,必须要指定一个端口号,这样就可以监听指定的端
口。
上面我们讲解了 DatagramSocket 的构造方法,接下来对 DatagramSocket 类中的常用方法进行详
细地讲解。
3.3UDP 网络程序
讲解了 DatagramPacket 和 DatagramSocket 的作用,接下来通过一个案例来学习一下它们在程序
中的具体用法。
下图为 UDP 发送端与接收端交互图解
传智播客——专注于 Java、.Net 和 Php、网页平面设计工程师的培训
要实现 UDP 通信需要创建一个发送端程序和一个接收端程序,很明显,在通信时只有接收端程
序先运行,才能避免因发送端发送的数据无法接收,而造成数据丢失。因此,首先需要来完成接收
端程序的编写。
UDP 完成数据的发送
/*
* 发送端
* 1,创建 DatagramSocket 对象
* 2,创建 DatagramPacket 对象,并封装数据
* 3,发送数据
* 4,释放流资源
*/
public class UDPSend {
public static void main(String[] args) throws IOException {
//1,创建 DatagramSocket 对象
DatagramSocket sendSocket = new DatagramSocket();
//2,创建 DatagramPacket 对象,并封装数据
//public DatagramPacket(byte[] buf, int length, InetAddress address, int
port)
//构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
byte[] buffer = "hello,UDP".getBytes();
DatagramPacket
DatagramPacket(buffer,
new
dp
=
buffer.length,
InetAddress.getByName("192.168.75.58"), 12306);
//3,发送数据
//public void send(DatagramPacket p) 从此套接字发送数据报包
sendSocket.send(dp);
//4,释放流资源
sendSocket.close();
}
}
UDP 完成数据的接收
/*
* UDP 接收端
*
* 1,创建 DatagramSocket 对象
* 2,创建 DatagramPacket 对象
* 3,接收数据存储到 DatagramPacket 对象中
* 4,获取 DatagramPacket 对象的内容
* 5,释放流资源
*/
public class UDPReceive {
public static void main(String[] args) throws IOException {
//1,创建 DatagramSocket 对象,并指定端口号
DatagramSocket receiveSocket = new DatagramSocket(12306);
传智播客——专注于 Java、.Net 和 Php、网页平面设计工程师的培训
//2,创建 DatagramPacket 对象, 创建一个空的仓库
byte[] buffer = new byte[1024];
DatagramPacket dp = new DatagramPacket(buffer, 1024);
//3,接收数据存储到 DatagramPacket 对象中
receiveSocket.receive(dp);
//4,获取 DatagramPacket 对象的内容
//谁发来的数据 getAddress()
InetAddress ipAddress = dp.getAddress();
String ip = ipAddress.getHostAddress();//获取到了 IP 地址
//发来了什么数据 getData()
byte[] data = dp.getData();
//发来了多少数据 getLenth()
int length = dp.getLength();
//显示收到的数据
String dataStr = new String(data,0,length);
System.out.println("IP 地址:"+ip+ "数据是"+ dataStr);
//5,释放流资源
receiveSocket.close();
}
}
第 4 章 TCP 通信
TCP 通信同 UDP 通信一样,都能实现两台计算机之间的通信,通信的两端都需要创建 socket
对象。
区别在于,UDP 中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发
送数据。
而 TCP 通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能
实现通信,服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接。
在 JDK 中提供了两个类用于实现 TCP 程序,一个是 ServerSocket 类,用于表示服务器端,一个
是 Socket 类,用于表示客户端。
通信时,首先创建代表服务器端的 ServerSocket 对象,该对象相当于开启一个服务,并等待客
户端的连接,然后创建代表客户端的 Socket 对象向服务器端发出连接请求,服务器端响应请求,两
者建立连接开始通信。
4.1ServerSocket
通过前面的学习知道,在开发 TCP 程序时,首先需要创建服务器端程序。JDK 的 java.net 包中
提供了一个 ServerSocket 类,该类的实例对象可以实现一个服务器段的程序。通过查阅 API 文档可
知,ServerSocket 类提供了多种构造方法,接下来就对 ServerSocket 的构造方法进行逐一地讲解。