Javase 基础加强 —— 12 网络编程
本系列为笔者学习Javase的课堂笔记,视频资源为B站黑马程序员出品的《黑马程序员Java+AI智能辅助编程全套视频教程,java零基础入门到大牛一套通关》,章节分布参考视频教程,为同样学习Javase系列课程的同学们提供参考。
01 概述
网络编程可以让设备中的程序与网络上其他设备中的程序进行数据交互的技术(实现网络通信)。
02 基本的通信架构
CS
架构(Client
客户端/Server
服务端)
BS
架构(Browser
浏览器/Server
服务端)
① Client - Server(CS)
架构
② Browser - Server(BS)
架构
java
提供了哪些网络编程解决方案?
java.net.*
包下提供了网络编程的解决方案!
03 网络编程三要素
04 IP
地址
IP(Internet Protocol)
全称为“互联网协议地址”,是分配给上网设备的唯一标识,目前,被广泛采用的IP
地址形式有两种:IPv4、IPv6
。
IPv4
IPv6
IPv6
是Internet Protocol version6
的缩写,它使用128位地址,号称可以为地球上的每一粒沙子编号。
IPV6
分成8段,每段每四位编码成一个十六进制位表示,每段之间用冒号(:)分开,将这种方式称为冒分十六进制。
IP
域名用于在互联网上识别和定位网站的人类可读的名称,比如说www.baidu.com
。
DNS
域名解析(Domain Name System)
是互联网中用于将域名转换为对应IP
地址的分布式命名系统。它充当了互联网的“电话簿”,将易记的域名映射到数字化的IP
地址,使得用户可以通过域名来访问网站和其他网络资源。
公网IP
: 是可以连接到互联网的IP
地址。
内网IP
: 也叫局域网IP
,是只能组织机构内部使用的IP
地址;例如,192.168
,开头的就是常见的局域网地址,范围为192.168.0.0 - 192.168.255.255
专门为组织机构内部使用。
本机IP
: 127.0.0.1、localhost
代表本机IP
,只会寻找当前程序所在的主机。
IP
常用命令:
ipconfig
查看本机IP
地址pingIP
地址检查网络是否连通
InetAddress
代表IP
地址。
package IPDemo;import java.net.InetAddress;public class GetIPDemo {public static void main(String[] args) {try{InetAddress ip1 = InetAddress.getLocalHost();System.out.println(ip1.getHostName());System.out.println(ip1.getHostAddress());InetAddress ip2 = InetAddress.getByName("www.baidu.com");System.out.println(ip2.getHostName());System.out.println(ip2.getHostAddress());System.out.println(ip2.isReachable(1000));}catch (Exception e){e.printStackTrace();}}
}
05 端口
端口用来标记正在计算机设备上运行的应用程序,被规定一个16
位的二进制,范围是0~65535
。
06 协议
网络上通信的设备,事先规定的连接规则,以及传输数据的规则被称为网络通信协议。
开放式网络互联标准:OSI
网络参考模型
国际标准:TCP/IP
网络模型
传输层的两个通信协议
① UDP(User Datagram Protocol)
用户数据报协议:无连接,不可靠通信,一般用于视频直播和语音通话。
不事先建立连接,数据按照包发,一包数据包含:自己的IP
、端口、目的地IP
、端口和数据(限制在64KB
内)等。发送方不管对方是否在线,数据在中间丢失也不管,如果接收方收到数据也不返回确认,故是不可靠的。
② TCP(Transmission Control Protocol)
传输控制协议:面向连接,可靠通信。
TCP
的最终目的要保证在不可靠的信道上实现可靠的数据传输。TCP
主要有三个步骤实现可靠传输,三次握手建立连接,传输数据进行确认,四次挥手断开连接。
07 UDP
通信的实现
Java
提供了一个java.net.DatagramSocket
类来实现UDP
通信。
UDPClientDemo.java
package UDPDemo;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UDPClientDemo {public static void main(String[] args) throws Exception {//目标:实现UDP通信,客户端开发System.out.println("客户端,启动!");//1.创建发送端对象DatagramSocket socket = new DatagramSocket();//2.创建数据对象(韭菜)byte[] bytes = "我是客户端,约你今晚啤酒、小龙虾、小烧烤".getBytes();DatagramPacket packet = new DatagramPacket(bytes, bytes.length, InetAddress.getLocalHost(), 8080);/*参数一:字节数组参数二:长度参数三:目的地IP地址 address参数四:服务端端口号 port*///3.发送数据socket.send(packet);}
}
UDPServerDemo.java
package UDPDemo;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UDPServerDemo {public static void main(String[] args) throws Exception {//目标:服务端开发System.out.println("服务端,启动!");//1.创建接收端对象,注册端口DatagramSocket socket = new DatagramSocket(8080);//2.创建数据包对象(韭菜盘子)byte[] buffer = new byte[1024 * 64];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);//3.接收数据socket.receive(packet);//4.确认收到int len = packet.getLength();String data = new String(buffer, 0, len);System.out.println("服务器收到了" + data);//5.获取对方IP地址和端口号String ip = packet.getAddress().getHostAddress();int port = packet.getPort();System.out.println("对方ip" + ip + "对方端口号" + port);}
}
升级版:多开多发
UDPClientDemo.java
package UDPDemo2;import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;public class UDPClientDemo {public static void main(String[] args) throws Exception {//目标:实现UDP通信,客户端开发System.out.println("客户端,启动!");//1.创建发送端对象DatagramSocket socket = new DatagramSocket();Scanner sc = new Scanner(System.in);while (true) {//2.创建数据对象(韭菜)System.out.println("请输入:");String msg = sc.nextLine();if("exit".equals(msg)){System.out.println("客户端,退出!");socket.close();break;}byte[] bytes = msg.getBytes();DatagramPacket packet = new DatagramPacket(bytes, bytes.length,InetAddress.getLocalHost(), 8080);//3.发送数据socket.send(packet);}}
}
UDPServerDemo.java
package UDPDemo2;import java.net.DatagramPacket;
import java.net.DatagramSocket;public class UDPServerDemo {public static void main(String[] args) throws Exception {//目标:服务端开发System.out.println("服务端,启动!");//1.创建接收端对象,注册端口DatagramSocket socket = new DatagramSocket(8080);while (true) {//2.创建数据包对象(韭菜盘子)byte[] buffer = new byte[1024 * 64];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);//3.接收数据socket.receive(packet);//4.确认收到int len = packet.getLength();String data = new String(buffer, 0, len);System.out.println("服务器收到了" + data);//5.获取对方IP地址和端口号String ip = packet.getAddress().getHostAddress();int port = packet.getPort();System.out.println("对方ip" + ip + "对方端口号" + port);System.out.println("--------------------------------");}}
}
08 TCP
通信的实现
Java
提供了一个java.net.Socket
类来实现TCP
通信。
TCPClientDemo.java
package TCPDemo;import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.logging.SocketHandler;public class TCPClientDemo {public static void main(String[] args) throws Exception {//目标:实现TCP通信,客户端开发System.out.println("客户端,启动!");//1.创建socket管道对象Socket socket = new Socket("127.0.0.1", 9999);//2.获取字节输出流OutputStream os = socket.getOutputStream();DataOutputStream dos = new DataOutputStream(os); //特殊输出流dos.writeInt(1);dos.writeUTF("亲爱的你想念自己吗?");//3.释放资源socket.close();}
}
TCPServerDemo.java
package TCPDemo;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class TCPServerDemo {public static void main(String[] args) throws Exception {//目标:服务端开发System.out.println("服务端,启动!");//1.创建server socket对象,注册端口ServerSocket ss = new ServerSocket(9999);Socket socket = ss.accept();//2.获取字节输入流InputStream is = socket.getInputStream();DataInputStream dis = new DataInputStream(is);int id = dis.readInt();String msg = dis.readUTF();System.out.println("id" + id + "msg" + msg);//3.获取对方IP地址和端口号System.out.println("对方ip"+ socket.getInetAddress().getHostAddress());System.out.println("对方端口号" + socket.getPort());}
}
升级版:多开多发
TCPClientDemo.java
package TCPDemo;import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
import java.util.logging.SocketHandler;public class TCPClientDemo {public static void main(String[] args) throws Exception {//目标:实现TCP通信,客户端开发System.out.println("客户端,启动!");//1.创建socket管道对象Socket socket = new Socket("127.0.0.1", 9999);//2.获取字节输出流OutputStream os = socket.getOutputStream();DataOutputStream dos = new DataOutputStream(os); //特殊输出流Scanner sc = new Scanner(System.in);while(true){System.out.println("请输入:");String msg = sc.nextLine();if("exit".equals(msg)){System.out.println("客户端,退出!");dos.close();socket.close();break;}dos.writeUTF(msg);dos.flush();}//3.释放资源socket.close();}
}
TCPServerDemo.java
package TCPDemo;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class TCPServerDemo {public static void main(String[] args) throws Exception {//目标:服务端开发System.out.println("服务端,启动!");//1.创建server socket对象,注册端口ServerSocket ss = new ServerSocket(9999);Socket socket = ss.accept();//2.获取字节输入流InputStream is = socket.getInputStream();DataInputStream dis = new DataInputStream(is);while (true) {String msg = dis.readUTF();System.out.println("msg" + msg);//3.获取对方IP地址和端口号System.out.println("对方ip"+ socket.getInetAddress().getHostAddress());System.out.println("对方端口号" + socket.getPort());System.out.println("-----------------------------------");}}
}
终极版:服务端同时与多个客户端连接
TCPServerDemo.java
package TCPDemo;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class TCPServerDemo {public static void main(String[] args) throws Exception {//目标:服务端 + 多线程System.out.println("服务端,启动!");//1.创建server socket对象,注册端口ServerSocket ss = new ServerSocket(9999);while(true){Socket socket = ss.accept(); //阻塞等待客户端连接new TCPServerReader(socket).start(); //启动独立子线程}}
}
TCPServerReader.java
package TCPDemo;import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;public class TCPServerReader extends Thread{private Socket socket;public TCPServerReader(Socket socket){this.socket = socket;}@Overridepublic void run(){try {//重写读取管道消息操作//2.获取字节输入流InputStream is = socket.getInputStream();DataInputStream dis = new DataInputStream(is);while (true) {String msg = dis.readUTF();System.out.println("msg" + msg);//3.获取对方IP地址和端口号System.out.println("对方ip"+ socket.getInetAddress().getHostAddress());System.out.println("对方端口号" + socket.getPort());System.out.println("-----------------------------------");}} catch (Exception e) {e.printStackTrace();}}
}
09 BS 架构原理:http://服务器IP:服务器端口
注:服务器必须给浏览器响应http
协议规定的数据格式,否则浏览器不识别返回的数据。
TCPServerDemo.java
package BSDemo;import java.net.ServerSocket;
import java.net.Socket;public class TCPServerDemo {public static void main(String[] args) throws Exception {//目标:BS架构原理System.out.println("服务端,启动!");//1.创建server socket对象,注册端口ServerSocket ss = new ServerSocket(8080);while(true){Socket socket = ss.accept(); //阻塞等待客户端连接System.out.println("客户端,上线!" + socket.getInetAddress().getHostAddress());new TCPServerReader(socket).start();}}
}
TCPServerReader.java
package BSDemo;import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;public class TCPServerReader extends Thread{private Socket socket;public TCPServerReader(Socket socket){this.socket = socket;}@Overridepublic void run(){try {//2. 响应网页数据给浏览器,将字节输出流包装成打印流OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);ps.println("HTTP/1.1 200 OK");ps.println("Content-Type:text/html;charset=utf-8");ps.println();ps.println("<html>");ps.println("<head>");ps.println("<meta charset='utf-8'>");ps.println("<title>");ps.println("名侦探柯南");ps.println("</title>");ps.println("</head>");ps.println("<body>");ps.println("<h1 style='color:red;font-size=20px'>真相只有一个</h1>");ps.println("</body>");ps.println("</html>");ps.close();socket.close();} catch (Exception e) {System.out.println("客户端,下线!" + socket.getInetAddress().getHostAddress());}}
}
升级版:线程池优化
TCPServerDemo.java
package BSDemo;import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;public class TCPServerDemo {public static void main(String[] args) throws Exception {//目标:BS架构原理System.out.println("服务端,启动!");//1.创建server socket对象,注册端口ServerSocket ss = new ServerSocket(8080);ExecutorService pool = new ThreadPoolExecutor(3, 10,10, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100),Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());while(true){Socket socket = ss.accept(); //阻塞等待客户端连接System.out.println("客户端,上线!" + socket.getInetAddress().getHostAddress());pool.execute(new TCPServerReader(socket)); //将客户端管道包装成任务交给线程池}}
}
TCPServerReader.java
package BSDemo;import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;public class TCPServerReader implements Runnable{private Socket socket;public TCPServerReader(Socket socket){this.socket = socket;}@Overridepublic void run(){try {//2. 响应网页数据给浏览器,将字节输出流包装成打印流OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);ps.println("HTTP/1.1 200 OK");ps.println("Content-Type:text/html;charset=utf-8");ps.println();ps.println("<html>");ps.println("<head>");ps.println("<meta charset='utf-8'>");ps.println("<title>");ps.println("名侦探柯南");ps.println("</title>");ps.println("</head>");ps.println("<body>");ps.println("<h1 style='color:red;font-size=20px'>真相只有一个</h1>");ps.println("</body>");ps.println("</html>");ps.close();socket.close();} catch (Exception e) {System.out.println("客户端,下线!" + socket.getInetAddress().getHostAddress());}}
}