15

网络编程

1. 概述

计算机网络:指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统。

网络编程的目的:传播交流信息、数据交换、通信。

达到效果需要什么:①如何准确地定位网络上的一台主机:×××.×××.×××.×××: port,定位到这个计算机上额某个资源;②找到了这个主机,如何传输数据?

javaweb -> 网页编程,B/S架构;网络编程 -> TCP/IP,C/S架构。

2. 网络通信的要素

如何实现网络的通信?

  • 通信双方地址:IP+端口号

  • 规则:网络通信协议(TCP/IP参考模型)

3. IP地址

IP地址:InetAddress

  • 唯一定位一台网络上的计算机

  • 127.0.0.1:本机localhost

  • IP地址的分类:

    • IPV4/IPV6

      • IPV4:4个字节组成(127.0.0.1),每个字节0~255,大概42亿个,2011年已用尽;

      • IPV6:128位,8个无符号整数

    • 公网(互联网)/私网(局域网,192.168.××.××,专门给组织内部使用的)

  • 域名:IP记忆问题

 1 package com.wang.demo01;
 2  3 import java.net.InetAddress;
 4 import java.net.UnknownHostException;
 5  6 // 测试IP
 7 public class TestInetAddress {
 8     public static void main(String[] args) {
 9         try {
10             // 查询本机地址
11             InetAddress inetAddress1 = InetAddress.getByName("127.0.0.1");
12             System.out.println(inetAddress1);
13             InetAddress inetAddress2 = InetAddress.getByName("localhost");
14             System.out.println(inetAddress2);
15             InetAddress inetAddress3 = InetAddress.getLocalHost();
16             System.out.println(inetAddress3);
17 18             // 查询网站IP地址
19             InetAddress inetAddress4 = InetAddress.getByName("www.baidu.com");
20             System.out.println(inetAddress4);
21 22             // 常用方法
23             System.out.println(inetAddress4.getAddress());
24             System.out.println(inetAddress4.getCanonicalHostName());    // 规范名字
25             System.out.println(inetAddress4.getHostAddress());          // IP
26             System.out.println(inetAddress4.getHostName());             // 域名,或者自己电脑的名字
27         } catch (UnknownHostException e) {
28             e.printStackTrace();
29         }
30     }
31 }

4. 端口

端口表示计算机上的一个程序的进程:

  • 不同的进程有不同的端口号,用来区分软件;

  • 被规定在0~65535;

  • TCP+UDP: 65535*2,单个协议下,端口号不能冲突;

  • 端口分类:

    • 公有端口(0~1023):HTTP: 80, HTTPS: 443, FTP: 21, Telent: 23;

    • 程序注册端口(1024~49151):分配给用户或者程序,Tomcat: 8080, MySQL: 3306, Oracle: 1521;

    • 动态、私有端口(49152~65535):尽量不要使用

      netstat -ano    # 查看所有的端口
      netstat -ano|findstr "5900"     # 查看指定的端口
      tasklist|findstr "8696"         # 查看指定端口的进程
      Ctrl + shift + ESC      # 打开任务管理器的快捷键
 1 package com.wang.demo01;
 2  3 import java.net.InetSocketAddress;
 4  5 public class TestInetSocketAddress {
 6     public static void main(String[] args) {
 7         InetSocketAddress socketAddress1 = new InetSocketAddress("127.0.0.1", 8080);
 8         InetSocketAddress socketAddress2 = new InetSocketAddress("localhost", 8080);
 9         System.out.println(socketAddress1);
10         System.out.println(socketAddress2);
11 12         System.out.println(socketAddress1.getAddress());
13         System.out.println(socketAddress1.getHostName());
14         System.out.println(socketAddress1.getPort());
15     }
16 }
17 // 输出:
18 /127.0.0.1:8080
19 localhost/127.0.0.1:8080
20 /127.0.0.1
21 127.0.0.1
22 8080

5. 通信协议

协议:约定

网络通信协议:速率,传输码率,代码结构,传输控制……

复杂问题 -> 分层

TCP/IP协议簇:实质上是一组协议

重点:

  • TCP:用户传输协议

  • UDP:用户数据报协议

TCP和UDP对比

  • TCP:打电话

    • 连接,稳定

    • 三次握手,四次挥手

      • 最少需要三次以保证稳定连接:

      •  

    • 客户端,服务端

    • 传输完成,释放连接,效率低

  • UDP:发短信

    • 不连接,不稳定

    • 客户端,服务端:没有明确的界限

    • 不管有没有准备好,都可以发送信息

    • DDoS:洪水攻击,分布式拒绝服务攻击

6. TCP

6.1 TCP聊天实现

服务器端:

  1. 建立服务的端口ServerSocket;

  2. 等待用户的连接 accept;

  3. 接收用户的消息。

 1 package com.wang.demo02;
 2  3 import java.io.ByteArrayOutputStream;
 4 import java.io.IOException;
 5 import java.io.InputStream;
 6 import java.net.ServerSocket;
 7 import java.net.Socket;
 8  9 // 服务器
10 public class TcpServerTest01 {
11     public static void main(String[] args){
12         ServerSocket serverSocket = null;
13         Socket socket = null;
14         InputStream is = null;
15         ByteArrayOutputStream baos = null;
16         try {
17             // 1. 先创建一个服务器地址
18             serverSocket = new ServerSocket(9999);
19             // 2. 等待客户端的连接请求
20             socket = serverSocket.accept();
21             // 3. 读取客户端的消息
22             is = socket.getInputStream();
23 24             // 管道流
25             baos = new ByteArrayOutputStream();
26             byte[] buffer = new byte[1024];
27             int len;
28             while ((len=is.read(buffer))!=-1){
29                 baos.write(buffer,0,len);
30             }
31             System.out.println(baos.toString());
32         } catch (IOException e) {
33             e.printStackTrace();
34         }finally {
35             if (baos!=null){
36                 try {
37                     baos.close();
38                 } catch (IOException e) {
39                     e.printStackTrace();
40                 }
41             }
42             if (is!=null){
43                 try {
44                     is.close();
45                 } catch (IOException e) {
46                     e.printStackTrace();
47                 }
48             }
49             if (socket!=null){
50                 try {
51                     socket.close();
52                 } catch (IOException e) {
53                     e.printStackTrace();
54                 }
55             }
56             if (serverSocket!=null){
57                 try {
58                     serverSocket.close();
59                 } catch (IOException e) {
60                     e.printStackTrace();
61                 }
62             }
63         }
64     }
65 }

客户端:

  1. 连接服务器Socket;

  2. 发送消息。

 1 package com.wang.demo02;
 2  3 import java.io.IOException;
 4 import java.io.OutputStream;
 5 import java.net.InetAddress;
 6 import java.net.Socket;
 7  8 // 客户端
 9 public class TcpClientTest01 {
10     public static void main(String[] args){
11         Socket socket = null;
12         OutputStream os = null;
13         try {
14             // 1. 获取服务器的地址,端口号
15             InetAddress serverIP = InetAddress.getByName("127.0.0.1");
16             int port = 9999;
17             // 2. 创建一个socket连接
18             socket = new Socket(serverIP, port);
19             // 3. 发送消息 IO流
20             os = socket.getOutputStream();
21             os.write("Hello, world!".getBytes());
22         } catch (Exception e) {
23             e.printStackTrace();
24         }finally {
25             if (os!=null){
26                 try {
27                     os.close();
28                 } catch (IOException e) {
29                     e.printStackTrace();
30                 }
31             }
32             if (socket!=null){
33                 try {
34                     socket.close();
35                 } catch (IOException e) {
36                     e.printStackTrace();
37                 }
38             }
39         }
40     }
41 }

6.2 TCP文件上传

服务器端:

 1 package com.wang.demo02;
 2  3 import java.io.File;
 4 import java.io.FileOutputStream;
 5 import java.io.InputStream;
 6 import java.io.OutputStream;
 7 import java.net.ServerSocket;
 8 import java.net.Socket;
 9 10 public class TcpServerTest02 {
11     public static void main(String[] args) throws Exception {
12         // 1. 创建服务
13         ServerSocket serverSocket = new ServerSocket(9000);
14         // 2. 监听客户端的连接
15         Socket socket = serverSocket.accept();  // 阻塞式监听,会一直等待客户端的连接
16         // 3. 获取输入流
17         InputStream is = socket.getInputStream();
18         // 4. 文件输出
19         FileOutputStream fos = new FileOutputStream(new File("recieved.jpg"));
20         byte[] buffer = new byte[1024];
21         int len;
22         while ((len=is.read(buffer))!=-1){
23             fos.write(buffer,0,len);
24         }
25         // 通知客户端接收完毕
26         OutputStream os = socket.getOutputStream();
27         os.write("Done!".getBytes());
28         // 5. 关闭资源
29         fos.close();
30         is.close();
31         socket.close();
32         serverSocket.close();
33     }
34 }

客户端:

 1 package com.wang.demo02;
 2  3 import java.io.*;
 4 import java.net.Socket;
 5  6 public class TcpClientTest02 {
 7     public static void main(String[] args) throws Exception {
 8         // 1. 创建一个Socket连接
 9         Socket socket = new Socket("127.0.0.1", 9000);
10         // 2. 创建一个输出流
11         OutputStream os = socket.getOutputStream();
12         // 3. 读取文件
13         FileInputStream fis = new FileInputStream(new File("JungKook.jpg"));
14         // 4. 写出文件
15         byte[] buffer = new byte[1024];
16         int len;
17         while ((len=fis.read(buffer))!=-1){
18             os.write(buffer,0,len);
19         }
20         // 通知服务器,文件传输完毕
21         socket.shutdownOutput();
22         // 确认服务器接收完毕,才能够断开连接
23         InputStream inputStream = socket.getInputStream();
24         ByteArrayOutputStream baos = new ByteArrayOutputStream();
25         byte[] buffer2 = new byte[1024];
26         int len2;
27         while ((len2=inputStream.read(buffer))!=-1){
28             baos.write(buffer,0,len2);
29         }
30         System.out.println(baos.toString());
31         // 5. 关闭资源
32         fis.close();
33         os.close();
34         socket.close();
35     }
36 }

Tomcat

服务器端:

  • 自定义 S

  • Tomcat服务器 S:Java后台开发

客户端:

  • 自定义 C

  • 浏览器 B

7. UDP

不用连接,但需要知道对方的地址

7.1 UDP消息发送

发送端:

 1 package com.wang.demo03;
 2  3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 import java.net.InetAddress;
 6  7 // 不需要连接服务器
 8 public class UdpClientTest01 {
 9     public static void main(String[] args) throws Exception {
10         // 1. 建立一个Socket
11         DatagramSocket socket = new DatagramSocket();
12         // 2. 创建数据包
13         String msg = "Hello, world!";
14         InetAddress localhost = InetAddress.getByName("localhost");
15         int port = 9090;
16         // param:数据,数据起始,数据长度,IP地址,端口
17         DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, localhost, port);
18         // 3. 发送数据包
19         socket.send(packet);
20         // 4. 关闭流
21         socket.close();
22     }
23 }

接收端:

 1 package com.wang.demo03;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 
 6 public class UdpServerTest01 {
 7     public static void main(String[] args) throws Exception {
 8         // 1. 开放端口
 9         DatagramSocket socket = new DatagramSocket(9090);
10         // 2. 接收数据包
11         byte[] buffer = new byte[1024];
12         DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
13         socket.receive(packet);     // 阻塞接收
14         System.out.println(packet.getAddress().getHostAddress());
15         System.out.println(new String(packet.getData()));
16         // 3. 关闭连接
17         socket.close();
18     }
19 }

7.2 UDP聊天实现

单工通信:一方是发送方,另一方是接收方

发送方:

 1 package com.wang.udpchat;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.InputStreamReader;
 5 import java.net.DatagramPacket;
 6 import java.net.DatagramSocket;
 7 import java.net.InetSocketAddress;
 8 
 9 public class UdpSenderDemo01 {
10     public static void main(String[] args) throws Exception {
11         DatagramSocket socket = new DatagramSocket(8888);
12 
13         // 准备发送数据,控制台读取
14         BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
15         while (true){
16             String data = reader.readLine();
17             byte[] sendData = data.getBytes();
18             DatagramPacket packet = new DatagramPacket(sendData, 0, sendData.length, new InetSocketAddress("localhost", 6666));
19             socket.send(packet);
20             if (data.equals("bye")){
21                 break;
22             }
23         }
24         socket.close();
25     }
26 }

接收方:

 1 package com.wang.udpchat;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 
 6 public class UdpRecieverDemo01 {
 7     public static void main(String[] args) throws Exception {
 8         DatagramSocket socket = new DatagramSocket(6666);
 9 
10         while (true){
11             // 准备接收数据
12             byte[] buffer = new byte[1024];
13             DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
14             socket.receive(packet);     // 阻塞式接收数据
15 
16             // 断开连接
17             byte[] data = packet.getData();
18             String recieveData = new String(data, 0, data.length);
19             System.out.println(recieveData);
20 
21             if (recieveData.equals("bye")){
22                 break;
23             }
24         }
25         socket.close();
26     }
27 }
半双工通信:双方都可以是发送方,也可以是接收方

发送端:

 1 package com.wang.udpchat02;
 2 
 3 import java.io.BufferedReader;
 4 import java.io.InputStreamReader;
 5 import java.net.DatagramPacket;
 6 import java.net.DatagramSocket;
 7 import java.net.InetSocketAddress;
 8 
 9 public class ChatSend implements Runnable{
10     DatagramSocket socket = null;
11     BufferedReader reader = null;
12 
13     private int fromPort;
14     private String toIP;
15     private int toPort;
16 
17     public ChatSend(int fromPort, String toIP, int toPort) {
18         this.fromPort = fromPort;
19         this.toIP = toIP;
20         this.toPort = toPort;
21 
22         try {
23             socket = new DatagramSocket(fromPort);
24             reader = new BufferedReader(new InputStreamReader(System.in));
25         } catch (Exception e) {
26             e.printStackTrace();
27         }
28     }
29 
30     @Override
31     public void run() {
32         while (true){
33             try {
34                 String data = reader.readLine();
35                 byte[] sendData = data.getBytes();
36                 DatagramPacket packet = new DatagramPacket(sendData, 0, sendData.length, new InetSocketAddress(this.toIP, this.toPort));
37                 socket.send(packet);
38                 if (data.equals("bye")){
39                     break;
40                 }
41             } catch (Exception e) {
42                 e.printStackTrace();
43             }
44         }
45         socket.close();
46     }
47 }

接收端:

 1 package com.wang.udpchat02;
 2 
 3 import java.net.DatagramPacket;
 4 import java.net.DatagramSocket;
 5 
 6 public class ChatRecieve implements Runnable{
 7     DatagramSocket socket = null;
 8     private int port;
 9     private String msgFrom;
10 
11     public ChatRecieve(int port, String msgFrom) {
12         this.port = port;
13         this.msgFrom = msgFrom;
14         try {
15             socket = new DatagramSocket(port);
16         } catch (Exception e) {
17             e.printStackTrace();
18         }
19     }
20 
21     @Override
22     public void run() {
23         while (true){
24             try {
25                 // 准备接收数据
26                 byte[] buffer = new byte[1024];
27                 DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
28                 socket.receive(packet);     // 阻塞式接收数据
29 
30                 // 断开连接
31                 byte[] data = packet.getData();
32                 String recieveData = new String(data, 0, data.length);
33                 System.out.println(msgFrom + ": " + recieveData);
34 
35                 if (recieveData.equals("bye")){
36                     break;
37                 }
38             } catch (Exception e) {
39                 e.printStackTrace();
40             }
41         }
42         socket.close();
43     }
44 }
45 package com.wang.udpchat02;
46 
47 public class ChatStudent {
48     public static void main(String[] args) {
49         // 开启两个线程
50         new Thread(new ChatSend(6666,"localhost",9999)).start();
51         new Thread(new ChatRecieve(8888,"teacher")).start();
52     }
53 }
54 package com.wang.udpchat02;
55 
56 public class ChatTeacher {
57     public static void main(String[] args) {
58         // 开启两个线程
59         new Thread(new ChatSend(7777,"localhost",8888)).start();
60         new Thread(new ChatRecieve(9999,"student")).start();
61     }
62 }

8. URL

统一资源定位符:用于定位资源,定位互联网上的某个资源。组成:

协议://ip地址:端口/项目名/资源

URL解析:

 1 package com.wang.urldemo;
 2  3 import java.net.MalformedURLException;
 4 import java.net.URL;
 5  6 public class URLTest01 {
 7     public static void main(String[] args) throws MalformedURLException {
 8         URL url = new URL("http://localhost:8080/helloword/index.jsp?username=JungKook&password=970901");
 9 10         System.out.println(url.getProtocol());  // 协议
11         System.out.println(url.getHost());      // 主机IP
12         System.out.println(url.getPort());      // 端口
13         System.out.println(url.getPath());      // 文件
14         System.out.println(url.getFile());      // 全路径
15         System.out.println(url.getQuery());     // 参数
16     }
17 }
18 // 结果:
19 http
20 localhost
21 8080
22 /helloword/index.jsp
23 /helloword/index.jsp?username=JungKook&password=970901
24 username=JungKook&password=970901

URL网络资源下载:

 1 package com.wang.urldemo;
 2  3 import java.io.FileOutputStream;
 4 import java.io.InputStream;
 5 import java.net.HttpURLConnection;
 6 import java.net.URL;
 7  8 public class URLDownloadTest {
 9     public static void main(String[] args) throws Exception {
10         // 1. 下载地址
11         URL url = new URL("https://c-ssl.duitang.com/uploads/item/201806/13/20180613121730_mhcxy.thumb.700_0.jpg");
12         // 2. 连接地址
13         HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
14 15         InputStream inputStream = urlConnection.getInputStream();
16         FileOutputStream fos = new FileOutputStream("jk.jpg");
17         byte[] buffer = new byte[1024];
18         int len;
19         while ((len=inputStream.read(buffer))!=-1){
20             fos.write(buffer,0,len);
21         }
22         fos.close();
23         inputStream.close();
24         urlConnection.disconnect();     // 断开连接
25     }
26 }

 附:狂神b站视频链接

原文地址:https://www.cnblogs.com/java-learning-xx/p/13886904.html