第11章 网络编程
IP 与端口、TCP 与 UDP、Socket 编程、URL 访问——让程序通过网络通信。
本章学习目标
- 理解 IP、端口、协议的作用
- 能用 Socket/ServerSocket 写 TCP 客户端与服务端
- 了解 UDP 的 DatagramSocket 用法
- 能用 URL 与 HttpURLConnection 访问网络资源
本章导览
核心内容
网络编程基础
定义:通过计算机网络可以使多台计算机实现连接,但是位于同一个网络中的计算机在进行连接和通信时必须要遵守一定的规则。在计算机网络中,这些连接和通信的规则被称为网络通信协议。
作用:它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交互。
分类:目前应用最广泛的有TCP/IP协议(Transmission Control Protocol/Internet Protocol,传输控制协议/英特网互联协议)、UDP协议(User Datagram Protocol,用户数据报协议)和其他一些协议的协议组。
说明:
为了减少网络编程设计的复杂性,绝大多数网络采用分层设计方法。
所谓分层设计,就是按照信息的流动过程将网络的整体功能分解为一个个的功能层,不同机器上的同等功能层之间采用相同的协议,同一机器上的相邻功能层之间通过接口进行信息传递。
TCP/IP协议(又称为TCP/IP协议簇)是一组用于实现网络互联的通信协议,其名称来源于该协议簇中的两个重要协议TCP协议和IP协议,基于TCP/IP协议参考模型的网络层次结构比较简单,共分为四层。
用于定义物理传输通道,通常是对某些网络连接设备的驱动协议,例如针对光纤、双绞线提供的驱动
是整个TCP/IP协议的核心,它主要用于将传输的数据进行分组,将分组数据发送到目标计算机或者网络
主要使网络程序进行通信,在进行网络通信时,可以采用TCP协议,也可以采用UDP协议
主要为互联网中的各种网络应用提供服务
要想使网络中的计算机能够进行通信,还必须为每台计算机指定一个标识号,通过这个标识号来指定接收数据的计算机或者发送数据的计算机。
在TCP/IP协议中,这个标识号就是IP地址,它可以唯一标识一台计算机,目前,IP地址广泛使用的版本是IPv4,它是由4个字节大小的二进制数来表示,如:00001010000000000000000000000001。
由于二进制形式表示的IP地址非常不便记忆和处理,因此通常会将IP地址写成十进制的形式,每个字节用一个十进制数字(0-255)表示,数字间用符号“.”分开表示4段数字,如“10.0.0.1”。
注意:
随着计算机网络规模的不断扩大,对IP地址的需求也越来越多,IPv4这种用4个字节表示的IP地址面临枯竭(实际情况是在2011年2月3日IPv4位地址已经分配完毕),因此IPv6 版本的IP地址便应运而生了。
IPv6使用16个字节表示IP地址,它所拥有的地址容量约是IPv4的8×1028倍,达到2128个(算上全零的),这样就解决了网络地址资源数量不足的问题。
组成:
为了便于寻址以及层次化构造网络,每个IP地址由两部分组成,即“网络.主机”的形式。
其中网络部分表示其属于互联网的哪一个网络,是网络的地址编码;
主机部分表示其属于该网络中的哪一台主机,是网络中一个主机的地址编码。
二者是主从关系。IP地址总共分为5类,常用的有A、B、C三类(另外的D和E类为特殊地址)。
1
A类地址:由第一段的网络地址和其余三段的主机地址组成,范围是1.0.0.0到127.255.255.255
2
B类地址:由前两段的网络地址和其余两段的主机地址组成,范围是128.0.0.0到191.255.255.255
3
C类地址:由前三段的网络地址和最后一段的主机地址组成,范围是192.0.0.0到223.255.255.255
4
D类地址:用于多点广播(Multicast),是一个专门保留的地址,并不指向特定的网络
5
E类地址:以“llll0”开始,为将来使用保留
注意:还有一个本地回环地址127.0.0.1,指本机地址,该地址一般用来测试使用。
通过IP地址可以连接到指定计算机,但如果想访问目标计算机中的某个应用程序,还需要指定端口号。
在计算机中,不同的应用程序是通过端口号区分的。
端口号是用两个字节(16位的二进制数)表示的,它的取值范围是0~65535;
其中,0~1023之间的端口号用于一些知名的网络服务和应用,用户的普通应用程序需要使用1024以上的端口号。
图示:
说明:从图可以看出,位于网络中一台计算机可以通过IP地址去访问另一台计算机,并通过端口号访问目标计算机中的某个应用程序
说明:在JDK中提供了一个与IP地址相关的InetAddress类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法。
| 方法声明 | 功能描述 |
|---|---|
| InetAddress getByName(String host) | 获取给定主机名的的IP地址,host参数表示指定主机 |
| InetAddress getLocalHost() | 获取本地主机地址 |
| String getHostName() | 获取本地IP地址的主机名 |
| boolean isReachable(int timeout) | 判断在限定时间内指定的IP地址是否可以访问 |
| String getHostAddress() | 获取字符串格式的原始IP地址 |
定义:UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。
使用UDP协议消耗资源小、通信效率高、延迟小,所以通常都会用于音频、视频和普通数据的传输,例如视频会议都使用UDP协议。
使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议。
定义:TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,保证了两台计算机之间可靠无差错的数据传输。
TCP协议传送速度较慢,但传送的数据比较可靠。
由于TCP协议的面向连接特性,它可以保证传输数据的安全性和完整性,所以是一个被广泛采用的协议,例如在下载文件时,如果数据接收不完整,将会导致文件数据丢失而不能被打开,因此,下载文件时必须采用TCP协议。
说明:在TCP连接中必须要明确客户端与服务器端,先由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”(具体如上图所示)。



📄 展开课件原文(第 7–20 页,共 14 页)
UDP通信
说明:
JDK中提供了一个DatagramPacket类,相当于一个集装箱,用于封装UDP通信中发送或者接收的数据。
JDK提供了与之对应的DatagramSocket类,该类的作用就类似于码头。
作用:DatagramPacket用于封装UDP通信中的数据。
创建发送端和接收端的DatagramPacket对象时,使用的构造方法有所不同。
接收端的构造方法只需要接收一个字节数组来存放接收到的数据。
发送端的构造方法不但要接收存放了发送数据的字节数组,还需要指定发送端IP地址和端口号。
DatagramPacket(byte[] buf,int length)。
指定了封装数据的字节数组和数据的大小,没有指定IP地址和端口号,这样的对象只能用于接收端。
DatagramPacket(byte[] buf,int offset,int length)
该构造方法与第1个构造方法类似同样用于接收端,只不过在第1个构造方法的基础上,增加了一个offset参数,该参数用于指定一个数组中发送数据的偏移量为offset,即从offset位置开始发送数据。
DatagramPacket(byte[] buf,int length,InetAddress addr,int port)
该构造方法不仅指定了封装数据的字节数组和数据的大小,还指定了数据包的目标IP地址(addr)和端口号(port)。该对象通常用于发送端。
DatagramPacket(byte[] buf,int offset,int length,InetAddress addr,int port)
该构造方法与第3个构造方法类似同样用于发送端,只不过在第3个构造方法的基础上,增加了一个offset参数,该参数用于指定一个数组中发送数据的偏移量为offset,即从offset位置开始发送数据。
| 方法声明 | 功能描述 |
|---|---|
| InetAddress getAddress() | 该方法用于返回发送端或者接收端的IP地址,如果是发送端的DatagramPacket对象,就返回接收端的IP地址;反之,就返回发送端的IP地址 |
| int getPort() | 该方法用于返回发送端或者接收端的端口号,如果是发送端的DatagramPacket对象,就返回接收端的端口号;反之,就返回发送端的端口号 |
| byte[] getData() | 该方法用于返回将要接收或者将要发送的数据,如果是发送端的DatagramPacket对象,就返回将要发送的数据;反之,就返回接收到的数据 |
| int getLength() | 该方法用于返回接收或者将要发送数据的长度,如果是发送端的DatagramPacket对象,就返回将要发送的数据长度;反之,就返回接收到数据的长度 |
DatagramSocket()
该构造方法用于创建发送端的DatagramSocket对象,并没有指定端口号,此时,系统会分配一个没有被其它网络程序所使用的端口号。
DatagramSocket(int port)
该构造方法既可用于创建接收端的DatagramSocket对象,也可以创建发送端的DatagramSocket对象,在创建接收端的DatagramSocket对象时,必须要指定一个端口号,这样就可以监听指定的端口。
DatagramSocket(int port,InetAddress addr)
该构造方法在创建DatagramSocket时,不仅指定了端口号还指定了相关的IP地址,这种情况适用于计算机上有多块网卡的情况,可以明确规定数据通过哪块网卡向外发送和接收哪块网卡的数据。
| 方法声明 | 功能描述 |
|---|---|
| void receive(DatagramPacket p) | 该方法用于接收DatagramPacket数据报,在接收到数据之前会一直处于阻塞状态,如果发送消息的长度比数据报长,则消息将会被截取 |
| void send(DatagramPacket p) | 该方法用于发送DatagramPacket数据报,发送的数据报中包含将要发送的数据、数据的长度、远程主机的IP地址和端口号 |
| void close() | 关闭当前的Socket,通知驱动程序释放为这个Socket保留的资源 |
说明:要实现UDP通信需要创建一个发送端程序和一个接收端程序,很明显,在通信时只有接收端程序先运行,才能避免因发送端发送的数据无法接收,而造成数据丢失。
示例:
案例演示(参考教材文件11-2&11-3)
任务案例
案例代码
接下来,通过多线程和UDP的相关知识,模拟实现一个聊天程序。请查看教材11.2.5小节。
📄 展开课件原文(第 21–30 页,共 10 页)
TCP通信
说明:
TCP通信同UDP通信一样,都能实现两台计算机之间的通信,通信的两端则都需要创建Socket对象。
TCP通信与UDP通信的其中一个主要区别在于,UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据;
而TCP通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,服务器端不可以主动连接客户端。
JDK中提供了ServerSocket类,表示服务器端;Socket类表示客户端。
通信时,首先要创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接;然后创建代表客户端的Socket对象,并向服务器端发出连接请求,服务器端响应请求,两者建立连接后可以正式进行通信。
ServerSocket()
该构造方法在创建ServerSocket对象时并没有指定端口号,使用时还需要调用bind(SocketAddress endpoint)方法将其绑定到指定的端口号上。
ServerSocket(int port)
该构造方法在创建ServerSocket对象时,可以绑定到指定的端口号上。如果port参数值为0,此时系统就会分配一个未被其他程序占用的端口号。由于客户端需要根据指定的端口号来访问服务器端程序,因此端口号随机分配的情况并不常用,通常都会给服务器端指定一个端口号。
ServerSocket(int port, int backlog)
该构造方法在第2个构造方法的基础上,增加了一个backlog参数。该参数用于指定在服务器忙时,可以与之保持连接请求的等待客户端数量,默认为50。
ServerSocket(int port, int backlog, InetAddress bindAddr)
该构造方法就是在第3个构造方法的基础上,指定了相关的IP地址,适用于计算机上有多块网卡和多个IP的情况,使用时可以明确规定ServerSocket在哪块网卡或IP地址上等待客户端的连接请求。
| 方法声明 | 功能描述 |
|---|---|
| Socket accept() | 该方法用于等待客户端的连接,在客户端连接之前一直处于阻塞状态,如果有客户端连接就会返回一个与之对应的Socket对象 |
| InetAddress getInetAddress() | 该方法用于返回一个InetAddress对象,该对象中封装了ServerSocket绑定的IP地址 |
| boolean isClosed() | 该方法用于判断ServerSocket对象是否为关闭状态,如果是关闭状态则返回true,反之则返回false |
| void bind(SocketAddress endpoint) | 该方法用于将ServerSocket对象绑定到指定的IP地址和端口号,其中参数endpoint 封装了IP 地址和端口号 |
Socket()
该构造方法在创建Socket对象时,并没有指定IP地址和端口号,创建对象后还需调用connect(SocketAddress endpoint)方法,才能完成与指定服务器端的连接,其中参数endpoint用于封装IP地址和端口号。
Socket(String host, int port)
该构造方法在创建Socket对象时,会根据参数去连接在指定地址和端口上运行的服务器程序,其中参数host接收的是一个字符串类型的IP地址。
Socket(InetAddress address, int port)
该方法在使用上与第2个构造方法类似,参数address用于接收一个InetAddress类型的对象,该对象用于封装一个IP地址。
| 方法声明 | 功能描述 |
|---|---|
| int getPort() | 该方法用于返回此Socket连接的远程服务端的端口号 |
| InetAddress getLocalAddress() | 该方法用于获取Socket对象绑定的本地IP地址,并将IP地址封装成InetAddress类型的对象返回 |
| void close() | 该方法用于关闭Socket连接,结束本次通信。在关闭Socket之前,应将与Socket相关的所有的输入/输出流全部关闭,这是因为一个良好的程序应该在执行完毕时释放所有的资源 |
| InputStream getInputStream() | 该方法返回一个InputStream类型的输入流对象。如果该对象是由服务器端的Socket返回,就用于读取客户端发送的数据;反之,用于读取服务器端发送的数据 |
| OutputStream getOutputStream() | 该方法返回一个OutputStream类型的输出流对象。如果该对象是由服务器端的Socket返回,就用于向客户端发送数据;反之,用于向服务器端发送数据 |
服务端与客户端通信图:
说明:要实现TCP通信需要创建一个服务器端程序和一个客户端程序,为了保证数据传输的安全性,首先需要实现服务器端程序,然后在编写客户端程序。
示例:
案例演示(参考教材文件11-7&11-8)
说明:实际上,很多服务器端程序都是允许被多个应用程序访问的,例如门户网站可以被多个用户同时访问,因此服务器端都是多线程的。
案例演示(参考教材文件11-9)
任务案例
案例代码
接下来,通过TCP通信的相关知识,来实现图片上传的功能。请查看教材11.3.6小节。

📄 展开课件原文(第 31–41 页,共 11 页)
本章小结
本章讲解了网络编程相关的基础知识。首先简要介绍网络编程的一些基础概念,包括网络通信协议、IP地址和端口号、InetAddress类以及UDP和TCP协议;接着讲解了UDP相关的DatagramSocket、DatagramPacket类,以及如何通过UDP通信实现简单的聊天程序;最后讲解了TCP中的ServerSocket、Socket类,以及如何通过TCP通信实现简单的文件上传。
📄 展开课件原文(第 42–43 页,共 2 页)
课件里的提醒 课件原文中的“注意 / 说明 / 定义”
- 定义:通过计算机网络可以使多台计算机实现连接,但是位于同一个网络中的计算机在进行连接和通信时必须要遵守一定的规则。在计算机网络中,这些连接和通信的规则被称为网络通信协议。
- 注意:还有一个本地回环地址127.0.0.1,指本机地址,该地址一般用来测试使用。
- 说明:从图可以看出,位于网络中一台计算机可以通过IP地址去访问另一台计算机,并通过端口号访问目标计算机中的某个应用程序
- 说明:在JDK中提供了一个与IP地址相关的InetAddress类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法。
- 定义:UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。
- 定义:TCP协议是面向连接的通信协议,即在传输数据前先在发送端和接收端建立逻辑连接,然后再传输数据,保证了两台计算机之间可靠无差错的数据传输。
- 说明:在TCP连接中必须要明确客户端与服务器端,先由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手”(具体如上图所示)。
- 说明:要实现UDP通信需要创建一个发送端程序和一个接收端程序,很明显,在通信时只有接收端程序先运行,才能避免因发送端发送的数据无法接收,而造成数据丢失。
- 说明:要实现TCP通信需要创建一个服务器端程序和一个客户端程序,为了保证数据传输的安全性,首先需要实现服务器端程序,然后在编写客户端程序。
- 说明:实际上,很多服务器端程序都是允许被多个应用程序访问的,例如门户网站可以被多个用户同时访问,因此服务器端都是多线程的。