【Java】Java网络编程

1、网络编程

1.1、概述

1、计算机网络是通过传输介质、通信设施和网络通信协议,把分散在不同地点的计算机设备互连起来,实现资源共享和数据传输的系统。网络编程就就是编写程序使联网的两个(或多个)设备(例如计算机)之间进行数据传输。Java语言对网络编程提供了良好的支持,通过其提供的接口我们可以很方便地进行网络编程。

2、Java是 Internet 上的语言,它从语言级上提供了对网络应用程 序的支持,程序员能够很容易开发常见的网络应用程序。

3、Java提供的网络类库,可以实现无痛的网络连接,联网的底层细节被隐藏在 Java 的本机安装系统里,由 JVM 进行控制。并 且 Java 实现了一个跨平台的网络库,程序员面对的是一个统一的网络编程环境。

1.2、计算机网络基础

1、概念

    把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大、功能强的网络系统,从而使众多的计算机可以方便地互相传递信息、 共享硬件、软件、数据信息等资源。

    计算机网络是计算机专业必修的一门学科!里面涉及到计算机之间的通信、网络安全等方方面面,有时间可以自行去学习,关于更多的网络基础知识这里就不一一介绍了。

2、网络编程的目的

    直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯。

3、网络编程中有两个主要的问题

    ①如何准确地定位网络上一台或多台主机;定位主机上的特定的应用

    ②找到主机后如何可靠高效地进行数据传输

1.3、网络通信要素概述

1、我们需要知道的是主机间通过网络进行通信是需要遵循网络通信协议,是通过IP地址准确定位主机,通过端口号准确定位主机上的应用。

IP地址和端口号

网络通信协议

2、如何实现网络中的主机互相通信?

① 通信双方地址:IP端口号

② 一定的规则(即:网络通信协议。有两套参考模型)

    OSI参考模型:模型过于理想化,未能在因特网上进行广泛推广。

    TCP/IP参考模型(或TCP/IP协议):事实上的国际标准。

3、网络通信协议(以TCP/IP模型为例)

TCP/IP,即Transmission Control Protocol/Internet Protocol的简写,中译名为传输控制协议/因特网互联协议,是Internet最基本的协议、Internet国际互联网络的基础。

1.4、IP地址和端口号(组合就是网络套接字)

我们知道IP地址和端口号是通信要素之一,它们可以唯一确定某一台主机的某个应用,并为主机之间通信提供了可能!那么什么是IP地址和端口号呢?

1、IP 地址:InetAddress(在Java中使用InetAddress类代表IP)

  • 一的标识 Internet 上的计算机(通信实体)

  • 本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost

  • P地址分类方式1:IPV4 和 IPV6

  • IPV4:4个字节组成,4个0-255。大概42亿,30亿都在北美,亚洲4亿。2011年初已 经用尽。以点分十进制表示,如192.168.0.1

  • IPV6:128位(16个字节),写成8个无符号整数,每个整数用四个十六进制位表示, 数之间用冒号(:)分开,如:3ffe:3201:1401:1280:c8ff:fe4d:db39:1984

  • IP地址分类方式2:公网地址(万维网使用)和私有地址(局域网使用)。192.168. 开头的就是私有址址,范围即为192.168.0.0–192.168.255.255,专门为组织机 构内部使用

  • 特点:不易记忆

2、InetAddress类

Internet上的主机有两种方式表示地址:

    ①域名(hostName):www.baidu.com

    ②IP 地址(hostAddress):14.215.177.38

InetAddress类主要表示IP地址,两个子类:Inet4Address、Inet6Address

InetAddress 类对象含有一个 Internet 主机地址的域名和IP地址:www.baidu.com 和 14.215.177.38

域名容易记忆,当在连接网络时输入一个主机的域名后,域名服务器(DNS) 负责将域名转化成IP地址,这样才能和主机建立连接。 -------域名解析

  代码示例:

 1 /**
 2  * 一、网络编程中有两个主要的问题:
 3  * 1.如何准确地定位网络上一台或多台主机;定位主机上的特定的应用
 4  * 2.找到主机后如何可靠高效地进行数据传输
 5  *
 6  * 二、网络编程中的两个要素:
 7  * 1.对应问题一:IP和端口号
 8  * 2.对应问题二:提供网络通信协议:TCP/IP参考模型(应用层、传输层、网络层、物理+数据链路层)
 9  *
10  *
11  * 三、通信要素一:IP和端口号
12  *
13  * 1. IP:唯一的标识 Internet 上的计算机(通信实体)
14  * 2. 在Java中使用InetAddress类代表IP
15  * 3. IP分类:IPv4 和 IPv6 ; 万维网 和 局域网
16  * 4. 域名:   www.baidu.com   www.mi.com  www.sina.com  www.jd.com
17  *            www.vip.com
18  * 5. 本地回路地址:127.0.0.1 对应着:localhost
19  *
20  * 6. 如何实例化InetAddress:两个方法:getByName(String host) 、 getLocalHost()
21  *        两个常用方法:getHostName() / getHostAddress()
22  *
23  * 7. 端口号:正在计算机上运行的进程。
24  * 要求:不同的进程有不同的端口号
25  * 范围:被规定为一个 16 位的整数 0~65535。
26  *
27  * 8. 端口号与IP地址的组合得出一个网络套接字:Socket
28  */
29 public class InetAddressTest {
30     public static void main(String[] args) {
31 
32         try {
33             InetAddress inet1 = InetAddress.getByName("192.168.1.4");
34             System.out.println(inet1);
35 
36             InetAddress inet2 = InetAddress.getByName("www.baidu.com");
37             System.out.println(inet2);
38 
39             InetAddress inet3 = InetAddress.getByName("127.0.0.1");
40             System.out.println(inet3);
41 
42             // 获取本地IP
43             InetAddress inet4 = InetAddress.getLocalHost();
44             System.out.println(inet4);
45 
46             // getHostName()
47             System.out.println(inet2.getHostName());
48             // getHostAddress()
49             System.out.println(inet2.getHostAddress());
50 
51         } catch (UnknownHostException e) {
52             e.printStackTrace();
53         }
54 
55     }
56 }

3、端口号

  • 端口号就是标识正在计算机上运行的进程(程序)
  • 不同的进程有不同的端口号
  • 被规定为一个 16 位的整数 0~65535。

端口分类:

① 公认端口:0~1023。被预先定义的服务通信占用(如:HTTP占用端口 80,FTP占用端口21,Telnet占用端口23)

② 注册端口:1024~49151。分配给用户进程或应用程序。(如:Tomcat占 用端口8080,MySQL占用端口3306,Oracle占用端口1521等)。

③ 动态/私有端口:49152~65535

4、端口号与IP地址的组合得出一个网络套接字:Socket

1.5、网络协议

1、网络通信协议

    计算机网络中实现通信必须有一些约定,即通信协议,对速率、传输代码、代 码结构、传输控制步骤、出错控制等制定标准。

2、问题:网络协议太复杂

    计算机网络通信涉及内容很多,比如指定源地址和目标地址,加密解密,压缩 解压缩,差错控制,流量控制,路由控制,如何实现如此复杂的网络协议呢?

3、通信协议分层的思想

    在制定协议时,把复杂成份分解成一些简单的成份,再将它们复合起来。最常 用的复合方式是层次方式,即同层间可以通信、上一层可以调用下一层,而与 再下一层不发生关系。各层互不影响,利于系统的开发和扩展。

4、TCP/IP协议簇

传输层协议中有两个非常重要的协议:

  • 传输控制协议TCP(Transmission Control Protocol)
  • 户数据报协议UDP(User Datagram Protocol)

TCP/IP 以其两个主要协议:传输控制协议(TCP)和网络互联协议(IP)而得 名,实际上是一组协议,包括多个具有不同功能且互为关联的协议。

IP(Internet Protocol)协议是网络层的主要协议,支持网间互连的数据通信。

TCP/IP协议模型从更实用的角度出发,形成了高效的四层体系结构,即物理链路层、IP层、传输层和应用层。

5、TCP 和 UDP

TCP协议:

✔ 使用TCP协议前,须先建立TCP连接,形成传输数据通道

✔ 传输前,采用“三次握手”方式,点对点通信,是可靠的

✔ TCP协议进行通信的两个应用进程:客户端、服务端。

✔ 在连接中可进行大数据量的传输

✔ 传输完毕,需释放已建立的连接,效率低

UDP协议:

✔ 将数据、源、目的封装成数据包,不需要建立连接

✔ 每个数据报的大小限制在64K内

✔ 发送不管对方是否准备好,接收方收到也不确认,故是不可靠的

✔ 可以广播发送

✔ 发送数据结束时无需释放资源,开销小,速度快

1.6、三次握手与四次挥手

  

  参考:https://blog.csdn.net/mulinsen77/article/details/88925672

2、TCP网络编程

2.1、Socket介绍

1、利用套接字(Socket)开发网络应用程序早已被广泛的采用,以至于成为事实 上的标准。

2、网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。

3、通信的两端都要有Socket,是两台机器间通信的端点。

4、网络通信其实就是Socket间的通信。

5、Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。

6、一般主动发起通信的应用程序属客户端,等待通信请求的为服务端。

7、Socket分类:

1. 流套接字(stream socket):使用TCP提供可依赖的字节流服务

2. 数据报套接字(datagram socket):使用UDP提供“尽力而为”的数据报服务

2.2、基于Socket的TCP编程

1、Java语言的基于套接字编程分为服务端编程和客户端编程,其通信模型如图所示

  

2、客户端Socket的工作过程包含以下四个基本的步骤:

  1. 创建 Socket:根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务端的通信路线。若连接失败,则会出现异常。

  2. 打开连接到 Socket 的输入/出流: 使用 getInputStream()方法获得输入流,使用 getOutputStream()方法获得输出流,进行数据传输

  3. 按照一定的协议对 Socket 进行读/写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入路线的信息),通过输出流将信息写入线程

  4. 关闭 Socket:断开客户端到服务器的连接,释放线路

3、客户端创建Socket对象:

客户端程序可以使用Socket类创建对象,创建的同时会自动向服务器方发起连接,Socket的构造器是:

1 // 构造器一
2 Socket(String host,int port)throws UnknownHostException,IOException
3 /* 向服务器(域名是 host。端口号为port)发起TCP连接,若成功,则创建Socket对象,否则抛出异常。*/
4 
5 // 构造器二
6 Socket(InetAddress address,int port)throws IOException
7 /* 根据InetAddress对象所表示的 IP地址以及端口号port发起连接。*/

客户端建立socketAtClient对象的过程就是向服务器发出套接字连接请,简要步骤如下

1 Socket s = new Socket("192.168.40.165",9999); // 1、创建Socket对象,指明服务端的IP和端口号
2 OutputStream out = s.getOutputStream(); // 2、获取一个输出流,用于输出数据
3 out.write("hello".getBytes()); // 3、写出数据
4 s.close(); // 4、回收资源

4、服务器(服务端)程序的工作过程包含以下四个基本的步骤:

  1. 调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口 上。用于监听客户端的请求。

  2. 调用 accept():监听连接请求,如果客户端请求连接,则接受连接,返回通信 套接字对象。

  3. 调用 该Socket类对象的 getOutputStream() 和 getInputStream ():获取输出 流和输入流,开始网络数据的发送和接收。

  4. 关闭ServerSocket和Socket对象:客户端访问结束,关闭通信套接字。

5、服务器建立 ServerSocket 对象

  1. ServerSocket 对象负责等待客户端请求建立套接字连接,类似邮局某个窗口 中的业务员。也就是说,服务器必须事先建立一个等待客户请求建立套接字 连接的ServerSocket对象。

  2. 所谓“接收”客户的套接字请求,就是accept()方法会返回一个 Socket 对象

1 ServerSocket ss = new ServerSocket(9999); // 1、创建服务端的ServerSocket,指明自己的端口号
2 Socket s = ss.accept (); // 2、调用accept()监听来自客户端的连接
3 InputStream in = s.getInputStream(); // 3、获取输入流,读取输入流的数据
4 byte[] buf = new byte[1024]; 
5 int num = in.read(buf); 
6 String str = new String(buf,0,num); 
7 System.out.println(s.getInetAddress().toString()+":"+str); 
8 s.close(); // 4、回收资源
9 ss.close();

2.3、TCP编程简单C/S通信示例

  1 /**
  2  * 实现TCP的网络编程
  3  * 例子1:客户端发送信息给服务端,服务端将数据显示在控制台上
  4  *
  5  */
  6 public class TCPTest1 {
  7 
  8     // 客户端
  9     @Test
 10     public void client() {
 11         Socket socket = null;
 12         OutputStream os = null;
 13         try {
 14             // 1.创建Socket对象,指明服务端的ip和端口号
 15             InetAddress inet = InetAddress.getByName("127.0.0.1");
 16             socket = new Socket(inet, 9090);
 17 
 18             // 2.获取一个输出流,用于输出数据
 19             os = socket.getOutputStream();
 20 
 21             // 3.写出数据的操作
 22             os.write("你好,我是客户端mm".getBytes());
 23         } catch (UnknownHostException e) {
 24             e.printStackTrace();
 25         } catch (IOException e) {
 26             e.printStackTrace();
 27         } finally {
 28             // 4.关闭资源
 29             if(os != null) {
 30                 try {
 31                     os.close();
 32                 } catch (IOException e) {
 33                     e.printStackTrace();
 34                 }
 35             }
 36             if(socket != null) {
 37                 try {
 38                     socket.close();
 39                 } catch (IOException e) {
 40                     e.printStackTrace();
 41                 }
 42             }
 43         }
 44     }
 45 
 46     // 服务端
 47     @Test
 48     public void server(){
 49         ServerSocket ss = null;
 50         Socket socket = null;
 51         InputStream is = null;
 52         ByteArrayOutputStream baos = null;
 53         try {
 54             // 1.创建服务端的ServerSocket,指明自己的端口号
 55             ss = new ServerSocket(9090);
 56 
 57             // 2.调用accept()表示接收来自客户端的socket
 58             socket = ss.accept();
 59 
 60             // 3.获取输入流
 61             is = socket.getInputStream();
 62 
 63             // 4.读取输入流中的数据
 64             baos = new ByteArrayOutputStream();
 65             byte[] buffer = new byte[5];
 66             int len;
 67             while ((len = is.read(buffer)) != -1) {
 68                 baos.write(buffer, 0, len);
 69             }
 70 
 71             System.out.println(baos.toString());
 72             System.out.println("收到来自于:" + socket.getInetAddress().getHostAddress() + "的数据");
 73         } catch (IOException e) {
 74             e.printStackTrace();
 75         } finally {
 76             // 关闭资源
 77             if(baos != null) {
 78                 try {
 79                     baos.close();
 80                 } catch (IOException e) {
 81                     e.printStackTrace();
 82                 }
 83             }
 84             if(is != null) {
 85                 try {
 86                     is.close();
 87                 } catch (IOException e) {
 88                     e.printStackTrace();
 89                 }
 90             }
 91             if(socket != null){
 92                 try {
 93                     socket.close();
 94                 } catch (IOException e) {
 95                     e.printStackTrace();
 96                 }
 97             }
 98             if(ss != null) {
 99                 try {
100                     ss.close();
101                 } catch (IOException e) {
102                     e.printStackTrace();
103                 }
104             }
105         }
106     }
107 }

2.4、TCP编程实现C/S文件传输

实现功能:客户端发送文件给服务端,服务端将文件保存在本地。

 1 /**
 2  * 实现TCP的网络编程
 3  * 例题2:客户端发送文件给服务端,服务端将文件保存在本地。
 4  */
 5 public class TCPTest2 {
 6 
 7     /*
 8     这里涉及到的异常,应该使用try-catch-finally处理
 9      */
10     @Test
11     public void client() throws IOException {
12         // 1.新建Socket
13         Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);
14         // 2、输出流
15         OutputStream os = socket.getOutputStream();
16         // 3、文件流
17         FileInputStream fis = new FileInputStream("beauty.jpg");
18         // 4.输出
19         byte[] buffer = new byte[1024];
20         int len;
21         while ((len = fis.read(buffer)) != -1) {
22             os.write(buffer, 0, len);
23         }
24         // 5.关闭资源
25         fis.close();
26         os.close();
27         socket.close();
28     }
29 
30     /*
31     这里涉及到的异常,应该使用try-catch-finally处理
32      */
33     @Test
34     public void server() throws IOException {
35         ServerSocket ss = new ServerSocket(9090);
36         Socket socket = ss.accept();
37 
38         InputStream is = socket.getInputStream();
39         FileOutputStream fos = new FileOutputStream("beauty2.jpg");
40 
41         byte[] buffer = new byte[1024];
42         int len;
43         while ((len = is.read(buffer)) != -1){
44             fos.write(buffer, 0, len);
45         }
46 
47         fos.close();
48         is.close();
49         socket.close();
50         ss.close();
51     }
52 }

2.5、TCP编程实现C/S信息反馈

实现功能:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给 客户端。并关闭相应的连接。

 1 /**
 2  * 实现TCP的网络编程
 3  * 例题3:从客户端发送文件给服务端,服务端保存到本地。并返回“发送成功”给客户端。
 4  */
 5 public class TCPTest3 {
 6 
 7     /*
 8     这里涉及到的异常,应该使用try-catch-finally处理
 9      */
10     @Test
11     public void client() throws IOException {
12         // 1.新建Socket
13         Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 9090);
14         // 2、输出流
15         OutputStream os = socket.getOutputStream();
16         // 3、文件流
17         FileInputStream fis = new FileInputStream("beauty.jpg");
18         // 4.输出
19         byte[] buffer = new byte[1024];
20         int len;
21         while ((len = fis.read(buffer)) != -1) {
22             os.write(buffer, 0, len);
23         }
24 
25         // 关闭数据输出
26         socket.shutdownOutput();
27 
28         InputStream is = socket.getInputStream();
29         ByteArrayOutputStream baos = new ByteArrayOutputStream();
30         byte[] buffer2 = new byte[1024];
31         int len2;
32         while ((len2 = is.read(buffer2)) != -1){
33             baos.write(buffer2, 0, len2);
34         }
35 
36         System.out.println(baos.toString());
37 
38         // 5.关闭资源
39         baos.close();
40         is.close();
41 
42         fis.close();
43         os.close();
44         socket.close();
45     }
46 
47     /*
48     这里涉及到的异常,应该使用try-catch-finally处理
49      */
50     @Test
51     public void server() throws IOException {
52         ServerSocket ss = new ServerSocket(9090);
53         Socket socket = ss.accept();
54 
55         InputStream is = socket.getInputStream();
56         FileOutputStream fos = new FileOutputStream("beauty3.jpg");
57 
58         byte[] buffer = new byte[1024];
59         int len;
60         while ((len = is.read(buffer)) != -1){
61             fos.write(buffer, 0, len);
62         }
63 
64         System.out.println("图片传输完成");
65 
66         OutputStream os = socket.getOutputStream();
67         os.write("你好,美女,照片我已收到,非常漂亮!".getBytes());
68 
69         os.close();
70         fos.close();
71         is.close();
72         socket.close();
73         ss.close();
74     }
75 }
View Code

3、UDP网络编程

3.1、UDP网络通信

1、类 DatagramSocket 和 DatagramPacket 实现了基于 UDP 协议网络程序。

2、UDP数据报通过数据报套接字 DatagramSocket 发送和接收,系统不保证 UDP数据报一定能够安全送到目的地,也不能确定什么时候可以抵达。

3、DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号。

4、UDP协议中每个数据报都给出了完整的地址信息,因此无须建立发送方和接收方的连接。如同发快递包裹一样。

3.2、UDP网络通信流程

1、DatagramSocket与DatagramPacket

2、建立发送端,接收端

3、建立数据包

4、调用Socket的发送、接收方法

5、关闭Socket

注意:发送端与接收端是两个独立的运行程序

3.3、UDP网络通信代码实现

 1 /**
 2  * UDP协议的网络编程
 3  */
 4 public class UDPTest {
 5 
 6     // 发送端
 7     @Test
 8     public void sender() throws IOException {
 9         DatagramSocket socket = new DatagramSocket();
10 
11         String str = "我是UDP方式发送的导弹";
12         byte[] data = str.getBytes();
13 
14         DatagramPacket packet = new DatagramPacket(data,
15                 0,
16                 data.length,
17                 InetAddress.getLocalHost(), 9090);
18 
19         socket.send(packet);
20 
21         socket.close();
22     }
23 
24     // 接收端
25     @Test
26     public void receiver() throws IOException {
27         DatagramSocket socket = new DatagramSocket(9090);
28 
29         byte[] buffer = new byte[1024];
30         DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
31 
32         socket.receive(packet);
33 
34         System.out.println(new String(packet.getData(), 0, packet.getLength()));
35 
36         socket.close();
37     }
38 }

4、URL网络编程

4.1、URL介绍

1、URL(Uniform Resource Locator):统一资源定位符,它表示 Internet 上某一 资源的地址。

2、它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate 这个资源。

3、通过 URL 我们可以访问 Internet 上的各种网络资源,比如最常见的 www,ftp 站点。浏览器通过解析给定的 URL 可以在网络上查找相应的文件或其他资源。

4、URL的基本结构由5部分组成: <传输协议>://<主机名>:<端口号>/<文件名>#片段名?参数列表

  1. 例如: http://192.168.1.100:8080/helloworld/index.jsp#a?username=shkstart&password=123

  2. #片段名:即锚点,例如看小说,直接定位到章节

  3. 参数列表格式:参数名=参数值&参数名=参数值…

5、Restful风格

一种软件架构风格、设计风格,而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。restful风格在实际开发中使用较多,对于URL地址有全新的使用方式,可以自行了解restful风格的使用!

4.2、URL类与类的构造器

1、为了表示URL,java.net 中实现了类 URL。我们可以通过下面的构造器来初 始化一个 URL 对象:

  1. public URL (String spec):通过一个表示URL地址的字符串可以构造一个URL对象。例如:URL url = new URL ("https://www.baidu.com/");

  2. public URL(URL context, String spec):通过基 URL 和相对 URL 构造一个 URL 对象。 例如:URL downloadUrl = new URL(url, “download.html");

  3. public URL(String protocol, String host, String file); 例如:new URL(“http”, “www.atguigu.com”, “download. html");

  4. public URL(String protocol, String host, int port, String file); 例如: URL gamelan = new URL(“http”, “www.atguigu.com”, 80, “download.html");

2、URL类的构造器都声明抛出非运行时异常,必须要对这一异常进行处理,通 常是用 try-catch 语句进行捕。

4.3、URL类常用方法

一个URL对象生成后,其属性是不能被改变的,但可以通过它给定的方法来获取这些属性:

  1. public String getProtocol( ) 获取该URL的协议名

  2. public String getHost( ) 获取该URL的主机名

  3. public String getPort( ) 获取该URL的端口号

  4. public String getPath( ) 获取该URL的文件路径

  5. public String getFile( ) 获取该URL的文件名

  6. public String getQuery( ) 获取该URL的查询名

参考:https://blog.csdn.net/m0_46357847/article/details/110272082

参考:https://www.cnblogs.com/swordfall/p/10781281.html

原文地址:https://www.cnblogs.com/h--d/p/14438146.html