15.1 网络编程概述
- Java是Internet上的语言,它从语言级别上提供了对网络应用程序的支持,程序员能够很容易开发常见的网络应用程序。
- Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在Java的本机安装系统里,由JVM进行控制。并且Java实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。
1、计算机网络
- 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地地互相传递信息、共享硬件、软件、数据信息等资源。
2、网络编程的目的
- 直接或间接地通过网络协议与其他计算机实现数据交换,进行通讯。
3、网络编程中有两个主要的问题
- 如何准确地定位网络上一台或多台主机;定位主机上的特定的应用。
- 找到主机后如何可靠高效地进行数据传输。
15.2 网络通信要素概述
1、如何实现网络中的主机互相通信
通信双方地址:
- IP
- 端口号
一定的规则(即:网络通信协议。有两套参考模型)
- OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广。
- TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。
15.3 通信要素1:IP和端口号
1、IP地址
唯一的标识Internet上的计算机(通信实体)。
本地回环地址(hostAddress):127.0.0.1
IP地址分类方式1:IPV4和IPV6
- IPV4:4个直接组成,4个0~255。大概42亿,30亿都在北美,亚洲4亿。2011年初已经用尽。以点分十进制表示,如192.168.0.1。
- IPV6:128位(16个字节),写成8个无符号整数,每个整数用4个十六进制表示,数之间用冒号(:)分开。
IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)。192.168.开头的就是私有地址,范围即为192.168.0.0~192.168.255.255,专门为组织机构内部使用。
特点:不易记忆。
在Java中使用InetAddress类代表IP。
import org.junit.jupiter.api.Test; import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressTest { @Test public void test() { try { InetAddress inet1 = InetAddress.getByName("192.168.10.14"); System.out.println(inet1); InetAddress inet2 = InetAddress.getByName("www.baidu.com"); System.out.println(inet2); InetAddress inet3 = InetAddress.getByName("127.0.0.1"); System.out.println(inet3); InetAddress inet4 = InetAddress.getLocalHost(); System.out.println(inet4); String hostName = inet2.getHostName(); String hostAddress = inet2.getHostAddress(); System.out.println("hostName=" + hostName + ",hostAddress=" + hostAddress); } catch (UnknownHostException e) { e.printStackTrace(); } } }
2、端口号
端口号标识正在计算机上运行的进程(程序)。
不同的进程有不同的端口号。
被规定为一个16位的整数:0~65535。
端口分类:
- 公认端口:0~1024。被预先定义的服务通信占用(如:HTTP占用端口80,FTP占用端口21,Telnet占用端口23)。
- 注册端口:1024~49151。分配给用户进程或应用程序。(如:Tomcat占用端口8080,MySQL占用端口3306,Oracle占用端口1521等)。
- 动态/私有端口:49152~65535。
端口号与IP地址的组合得出一个网络套接字:Socket。
15.4 通信要素2:网络协议
1、TCP/IP协议簇
- 传输层协议中有两个非常重要的协议:
- 传输控制协议TCP(Transmission Control Protocol)
- 用户数据报协议UDP(User Datagram Protocol)
- TCP/IP以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得名,实际上是一组协议,包括多个具有不同功能而且互为关联的协议。
- IP(Internet Protocol)协议是网络层的主要协议,支持网络间互连的数据通信。
- TCP/IP协议模型从更使用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层。
2、TCP、UDP
TCP协议:
- 使用TCP协议前,须先建立TCP连接,形成传输数据通道。
- 传输前,采用“三次握手”方式,点对点通信,是可靠的。
- TCP协议进行通信的两个应用共进程:客户端、服务端。
- 在连接中可进行大数据量的传输。
- 传输完毕,需“四次挥手”释放已建立的连接,效率低。
UDP协议:
- 将数据、源、目的封装成数据包,不需要建立连接。
- 每个数据报的大小限制在64K内。
- 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的。
- 可以广播发送。
- 发送数据结束时无需释放资源,开销小,速度快。
15.5 TCP网络编程
客户端:
- 创建Socket对象,指明服务器端的IP和端口号。
- 获取一个输出流,用于输出数据。
- 写出数据的操作。
- 关闭资源。
服务器端:
- 创建服务器端的ServerSocket,指明自己的端口号。
- 调用accept(),表示接收来自客户端的socket。
- 获取输入流。
- 读取输入流中的数据。
- 关闭资源。
示例1:
import org.junit.jupiter.api.Test; import java.io.*; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; /** * 实现TCP的网络编程 * 例子1:客户端发送信息给服务端,服务端将数据显示在控制台上。 */ public class TCPTest { // 客户端 @Test public void clent() { Socket socket = null; OutputStream os = null; try { // 1、创建Socket对象,指明服务器端的IP和端口号 InetAddress inet = InetAddress.getByName("127.0.0.1"); socket = new Socket(inet, 8899); // 2、获取一个输出流,用于输出数据 os = socket.getOutputStream(); // 3、写出数据 os.write("你好,我是客户端".getBytes()); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 4、关闭资源 if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Test public void server() { InputStream is = null; Socket socket = null; ByteArrayOutputStream bao = null; ServerSocket ss = null; try { // 1、创建服务器端的ServerSocket,指明自己的端口号 ss = new ServerSocket(8899); // 2、调用accept()方法,表示接收来自于客户端的socket socket = ss.accept(); // 3、获取输入流 is = socket.getInputStream(); // 4、读取输入流中的数据 bao = new ByteArrayOutputStream(); byte[] buffer = new byte[5]; int len; while ((len = is.read(buffer)) != -1) { bao.write(buffer, 0, len); } System.out.println(bao.toString()); System.out.println("收到了来自于:"+socket.getInetAddress().getHostAddress()+"的数据"); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 5、关闭资源 if (bao != null) { try { bao.close(); } catch (IOException e) { e.printStackTrace(); } } if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (ss != null) { try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
示例2:
import org.junit.jupiter.api.Test; import java.io.*; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; /** * 实现TCP的网络编程 * 例子2:客户端发送文件给服务端,服务端将文件保存在本地。 */ public class TCPTest { // 客户端 @Test public void clent() { Socket socket = null; OutputStream os = null; FileInputStream fis = null; try { socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090); os = socket.getOutputStream(); fis = new FileInputStream(new File("hello.txt")); byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { os.write(buffer, 0, len); } } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 4、关闭资源 if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Test public void server() { ServerSocket ss = null; Socket socket = null; InputStream is = null; FileOutputStream fos = null; try { ss = new ServerSocket(9090); socket = ss.accept(); is = socket.getInputStream(); fos = new FileOutputStream(new File("hello1.txt")); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } } catch (IOException e) { e.printStackTrace(); } finally { if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (ss != null) { try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
示例3:
import org.junit.jupiter.api.Test; import java.io.*; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; /** * 实现TCP的网络编程 * 例子3:客户端发送文件给服务端,服务端将文件保存在本地,并给客户端回复。 */ public class TCPTest { // 客户端 @Test public void clent() { Socket socket = null; OutputStream os = null; FileInputStream fis = null; InputStream is = null; ByteArrayOutputStream baos = null; try { socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090); os = socket.getOutputStream(); fis = new FileInputStream(new File("hello.txt")); byte[] buffer = new byte[1024]; int len; while ((len = fis.read(buffer)) != -1) { os.write(buffer, 0, len); } socket.shutdownOutput(); // 接受来自服务器端的数据 is = socket.getInputStream(); baos = new ByteArrayOutputStream(); byte[] buffer2 = new byte[20]; int len2; while ((len2 = is.read(buffer2)) != -1) { baos.write(buffer2, 0, len2); } System.out.println(baos.toString()); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { // 4、关闭资源 if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (baos != null) { try { baos.close(); } catch (IOException e) { e.printStackTrace(); } } if (fis != null) { try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } } } @Test public void server() { ServerSocket ss = null; Socket socket = null; InputStream is = null; FileOutputStream fos = null; OutputStream os = null; try { ss = new ServerSocket(9090); socket = ss.accept(); is = socket.getInputStream(); fos = new FileOutputStream(new File("hello1.txt")); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } // 服务器端给客户端反馈 os = socket.getOutputStream(); os.write("文件已收到".getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { if (os != null) { try { os.close(); } catch (IOException e) { e.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (socket != null) { try { socket.close(); } catch (IOException e) { e.printStackTrace(); } } if (ss != null) { try { ss.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
15.6 UDP网络编程
类DatagramSocket和DatagramPacket实现了基于UDP协议网络程序。
UDP数据报通过数据报套接字DatagramSocket发送和接收,系统不保证UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。
DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。
UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。如同发快递包裹一样。
import org.junit.jupiter.api.Test; import java.io.IOException; import java.net.*; /** * UDP的网络编程 */ public class UDPTest { // 发送端 @Test public void sender() throws IOException { DatagramSocket socket = new DatagramSocket(); String str = "我是UDP方式发送的导弹"; byte[] data = str.getBytes(); InetAddress inet = InetAddress.getLocalHost(); DatagramPacket packet = new DatagramPacket(data, 0, data.length, inet, 9090); socket.send(packet); socket.close(); } // 接收端 @Test public void receiver() throws IOException { DatagramSocket socket = new DatagramSocket(9090); byte[] buffer = new byte[100]; DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length); socket.receive(packet); System.out.println(new String(packet.getData(), 0, packet.getLength())); socket.close(); } }
15.7 URL编程
1、URL类
URL(Uniform Resource Locator):同一资源定位符,它表示Internet上某一资源的地址。
它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。
通过URL我们可以访问Internet上的各种网络资源,比如最常见的www、ftp站点。浏览器通过解析给定URL可以在网络上查找相应的文件或其他资源。
URL的基本结构由5部分组成:
<传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表
片段名,即锚点。例如看小说,直接定位到章节。
参数列表格式:参数名=参数值&参数名=参数值……
import org.junit.jupiter.api.Test; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; /** * URL网络编程。 */ public class URLTest { @Test public void test1() { try { URL url = new URL("https://blog.nowcoder.net/n/ca1e5c2a9e49434d993c7c908f509191"); System.out.println(url.getProtocol()); System.out.println(url.getHost()); System.out.println(url.getPort()); System.out.println(url.getPath()); System.out.println(url.getFile()); System.out.println(url.getQuery()); } catch (MalformedURLException e) { e.printStackTrace(); } } // 利用URL下载网络资源。 @Test public void test2() { HttpURLConnection urlConnection = null; InputStream is = null; FileOutputStream fos = null; try { URL url = new URL("https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=2359239511,1787283821&fm=26&gp=0.jpg"); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.connect(); is = urlConnection.getInputStream(); fos = new FileOutputStream("java.jpg"); byte[] buffer = new byte[1024]; int len; while ((len = is.read(buffer)) != -1) { fos.write(buffer, 0, len); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (is != null) { try { is.close(); } catch (IOException e) { e.printStackTrace(); } } if (fos != null) { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } if (urlConnection != null) { urlConnection.disconnect(); } } } }