1、网络编程概述
Java是Internet上的语言,从语言层面提供了对网络应用程序的支持,便于开发网络应用程序
Java提供网络类库,将联网的底层细节隐藏,由JVM控制,提供统一的网络编程环境
- 计算机网络概念:把分布在不同地理区域的计算机与专门的外部设备通信线路连接的规模大、功能强的网络系统。便于计算机之间信息的传递
- 网络编程的目的:直接或间接的通过网络协议与其它计算机实现数据交换和通信
- 网络编程实现的问题点:1、如何准确的定位网络上的一台或多台计算机(主机定位);2、找到主机后如何可靠高效的进行数据传输
2、网络通信要点
2-1、IP和端口号
网络中通信双方法的地址
2-2、网络通信协议
- 通信的规则(网络通信协议:OSI参考模型【理想的模型】、TCP/IP参考模型【实际使用】)
- 对速率、传输代码、代码结构、传输控制结构、出错控制等的规定
- 网络通信协议利用分层简化复杂的考虑要素(指定源地址和目标地址、加密和解密、压缩和解压缩、差错控制、流量控制、路由控制等)
- 通信协议中的分层思想:先分解为简单的成分,再复合起来,同层间可以通信;上一层可以调用下一层,各层不影响,便于拓展和开发
2-3、数据传输示例
3、通信要素1——IP和端口
IP地址:InetAddress——唯一标识Internet上的计算机(通信实体)
本地回环地址(HostAddresss)——127.0.0.1
主机名(HostName)——Localhost
IP地址分类:1、IPv4 & IPv6 2、公网地址 & 私有地址
3-1、InetAddress类
Java中的IP类:1、通过get方法,获取该类的对象;2、通过域名(网址)获取类对象;
IP类的特殊对象:本地回路地址LocalHIst 127.0.0.1——本机IP地址
1、通过具体的IP地址,获取InetAddress类对象
InetAddress.getByName("192.168.10.14");
2、通过域名获取InetAddress类对象
InetAddress.getByName("www.baidu.com");
域名 → 本机Host → DNS服务器 …… → 实际网络服务器
3、特别的InetAddress类对象
localHost 127.0.0.1 本地回路地址
getLocalHost() 获取本机IP地址
4、InetAddress类常用的方法:获取本地ip
getHostName()
getHostAddress()
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressTest {
public static void main(String[] args) throws UnknownHostException {
//1、通过get方法获取InetAddress类的对象
InetAddress inet1 = InetAddress.getByName("192.168.10.14");
//2、通过域名获取InetAddress类的对象
InetAddress inet2 = InetAddress.getByName("www.baidu.com");
//3、本地回路地址127.0.0.1 localHost 和本机ip
System.out.println(InetAddress.getByName("localhost"));
System.out.println(InetAddress.getLocalHost());
//4、常用方法
System.out.println(inet2.getHostName());
System.out.println(inet2.getHostAddress());
}
}
3-2、端口号
端口号标识计算机正在运行的进程(程序)
不同的进程有不同的端口号,15位的整数:0-65535
端口分类:公认端口-0-1023——被预先定义的服务通信占用(HTTP80、FTP21、TeInet23)
注册端口:1024-49151——分配给用户进程或程序(Tomcat8080、MySQL3306、Oracle1521)
动态/私有端口:49152-65535
端口和IP地址结合得到网络套接字——Socket【程序(进程)之间定位实现】
4、通信要素2——网络协议
传输层协议中的两个重要协议:
- 传输控制协议TCP——Transmission Control Protocol
- 用户数据协议UDP——User Datagram Protocol
TCP/IP协议簇以【TCP协议】【IP协议:网络互联协议】得名——具有不同功能,相互关联的协议组
IP协议Internet Protocol:是网络层的主要协议,支持网间互联的数据通信
TCP/IP协议模型,从实际的角度出发,形成了高效的四层体系结构(物理链路层、IP层、传输层、应用层)
4-1、TCP和UDP的差异
TCP:
- 使用TCP协议前,需要先建立TCP连接,形成传输数据通道
- 传输前,采用”三次握手“方式,点对点通信,可靠
- TCP协议进行通信的两个进程客户端和服务端
- 在连接中可进行大量数据的传输
- 传输完毕,需释放已经建立的连接,效率低
UDP:
- 将数据、源、目的封装成数据包,不需要建立连接
- 每个数据包的大小限制在64K内
- 发送不管对方是否准备好,接收方收到也不确认,不可靠
- 可以广播发送
- 发送数据结束时,无需释放资源,开销小,速度快
TCP建立连接:三次握手;释放连接:四次你挥手
客户端和服务端,都可以挥手(实际一般都是客户端发起挥手)
5、TCP网络编程
5-1、客户端发送内容给服务器端,服务端将内容打印到控制台上
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* @ClassName:TCPTest1
* @Description: TODO
* @Author ChenS
* @create 2021-06-27-4:40 PM
* @Version 1.0
*/
//程序运行如果端口报错,可临时切换端口号解决
public class TCPTest1 {
public static void main(String[] args) {
//准备两个线程分别运行客户端和服务器端
//先启动服务端
new Thread(new Runnable() {
@Override
public void run() {
try {
server1.receiveMessage(7799);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
//再启动客户端
new Thread(new Runnable() {
@Override
public void run() {
try {
client1.sendMessage("这一条信息来自客户端", "127.0.0.1", 7799);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
class client1{
public static void sendMessage(String meg,String ip,int port) throws IOException {
//创建InetAddress对象
InetAddress inet1 = InetAddress.getByName(ip);
//创建用于发送的Socket
Socket socket = new Socket(inet1, port);
//调用方法,获取需要输出的流
OutputStream outputStream = socket.getOutputStream();
//向输出流中添加信息
outputStream.write(meg.getBytes());
//关闭资源
socket.close();
outputStream.close();
}
}
class server1{
public static void receiveMessage(int port) throws IOException {
//创建serverSocket
ServerSocket serverSocket = new ServerSocket(port);
//调用方法,获取客户端传输的socket
Socket acceptedSocket = serverSocket.accept();
//调用方法,获取socket中的流
InputStream inputStream = acceptedSocket.getInputStream();
//为避免传输的文字乱码,使用字节数组输出流接受信息
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//处理数据
byte[] bytes = new byte[5];
int len;
while ((len = inputStream.read(bytes)) != -1){
byteArrayOutputStream.write(bytes,0,len);
}
System.out.println(byteArrayOutputStream.toString());
System.out.println("接收到了来自:" + acceptedSocket.getLocalAddress() + "的信息");
//关闭资源
serverSocket.close();
acceptedSocket.close();
inputStream.close();
byteArrayOutputStream.close();
}
}
5-2、客户端发送文件给服务器端,服务端将文件保存到本地
import java.io.*;
import java.net.*;
/**
* @ClassName:TCPTest2
* @Description: TODO
* @Author ChenS
* @create 2021-06-27-5:43 PM
* @Version 1.0
*/
//报异常未找到文件,可切换目的文件地址解决
public class TCPTest2 {
public static void main(String[] args) {
String srcFilePath = "D:\\ LOL\\如何自学Java:入门与编程技能训练.pptx";
String desFilePath = "D:\\AA\\如何自学Java:入门与编程技能训练.pptx";
String ip = "127.0.0.1";
int port = 8991;
new Thread(new Runnable() {
@Override
public void run() {
try {
Server2.receiveFile(desFilePath, port );
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Client2.sendFile(srcFilePath, ip, port);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
class Client2{
public static void sendFile(String srcFilePath,String ip,int port) throws IOException {
//1、创建Socket对象
Socket socket = new Socket(InetAddress.getByName(ip), port);
//2、调用方法,获取输出流
OutputStream outputStream = socket.getOutputStream();
//3、准备File对象 和输入流
FileInputStream fileInputStream = new FileInputStream(new File(srcFilePath));
//4、读写数据操作
byte[] bytes = new byte[1024];
int len;
while ((len = fileInputStream.read(bytes)) != -1){
outputStream.write(bytes,0,len);
}
//关闭资源
fileInputStream.close();
outputStream.close();
socket.close();
}
}
class Server2{
public static void receiveFile(String desFilePath,int port) throws IOException {
//1、创建服务端Socket
ServerSocket serverSocket = new ServerSocket(port);
//2、调用方法,获取客户端Socket
Socket accept = serverSocket.accept();
//3、调用方法,获取输入流
InputStream inputStream = accept.getInputStream();
//4、准备File 和 输出流
FileOutputStream fileOutputStream = new FileOutputStream(new File(desFilePath));
//5、操作文件
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1){
fileOutputStream.write(bytes,0 ,len);
}
System.out.println("接收完毕");
//6、关闭资源
serverSocket.close();
accept.close();
inputStream.close();
fileOutputStream.close();
}
}
5-3、从客户端发送文件给服务器端。服务端保存到本地,并返回”发送成功“给客户端
注意建立的连接Socket只有一个,因此在使用Socket获取输出流或者输入流,操作结束后,应该关闭流对Socket的占用(此时是阻塞式的,需要手动解除Socket占用)
socketFromClient.shutdownOutput();//关闭Socket中的输出流
socketFromClient.shutdownInput();//关闭Socket中的输入流
import java.io.*;
import java.net.*;
public class TCPTest2 {
public static void main(String[] args) {
String srcFilePath = "D:\\ LOL\\如何自学Java:入门与编程技能训练.pptx";
String desFilePath = "D:\\AA\\如何自学Java:入门与编程技能训练.pptx";
String ip = "127.0.0.1";
int port = 8991;
new Thread(new Runnable() {
@Override
public void run() {
try {
Server2.receiveFile(desFilePath, port );
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Client2.sendFile(srcFilePath, ip, port);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
class Client2{
public static void sendFile(String srcFilePath,String ip,int port) throws IOException {
//1、创建Socket对象
Socket socketFromClient = new Socket(InetAddress.getByName(ip), port);
//2、调用方法,获取输出流
OutputStream outputStream = socketFromClient.getOutputStream();
//3、准备File对象 和输入流
FileInputStream fileInputStream = new FileInputStream(new File(srcFilePath));
//4、读写数据操作
byte[] bytes = new byte[1024];
int len;
while ((len = fileInputStream.read(bytes)) != -1){
outputStream.write(bytes,0,len);
}
socketFromClient.shutdownOutput();//关闭Socket中的输出流
//接受来自服务端确认信息
InputStream inputStream = socketFromClient.getInputStream();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] bytes1 = new byte[24];
int len1;
while ((len1 = inputStream.read(bytes1)) != -1){
byteArrayOutputStream.write(bytes1,0,len1);
}
System.out.println(byteArrayOutputStream.toString());
//关闭资源
fileInputStream.close();
outputStream.close();
socketFromClient.close();
inputStream.close();
byteArrayOutputStream.close();
}
}
class Server2{
public static void receiveFile(String desFilePath,int port) throws IOException {
//1、创建服务端Socket
ServerSocket serverSocket = new ServerSocket(port);
//2、调用方法,获取客户端Socket
Socket socketFromClient = serverSocket.accept();
//3、调用方法,获取输入流
InputStream inputStream = socketFromClient.getInputStream();
//4、准备File 和 输出流
FileOutputStream fileOutputStream = new FileOutputStream(new File(desFilePath));
//5、操作文件
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1){
fileOutputStream.write(bytes,0 ,len);
}
socketFromClient.shutdownInput();//关闭Socket输入流
System.out.println("接收完毕(来自服务端)");
//使用得到的客户端Socket的输出流,并写入字符串
OutputStream outputStream = socketFromClient.getOutputStream();
outputStream.write("文件复制完成(来自服务端)".getBytes());
//6、关闭资源
serverSocket.close();
socketFromClient.close();
inputStream.close();
fileOutputStream.close();
outputStream.close();
}
}
练习1:服务端,读取本地图片,发送给客户端
练习2:客户端发送文本给服务端,服务端返回给客户端全部转化为大写的文本
5-4、客户端访问服务端资源演示
- 客户端:自定义、浏览器
- 服务端:自定义、Tomcat
1、安装启动Tomcat服务器、启动服务
2、创建服务器中资源文件
3、通过浏览器,直接访问资源文件LocalHost:8080\xxx
6、UDP网络编程
- 类DatagramSocket 和DatagramPacket实现类基于UDP协议的网络程序
- UDP数据报通过数据套接字SatagramSocket发送和接收【系统不保证UDP数据报一定能安全送达目的地,也不确定什么时候可以送达】
- DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端IP地址、端口、以及接受端的IP和端口
- UDP协议中每个数据报,都给出类完整的地址信息,因此无需建立发送方和接受方的连接:一个只管发、一个只管收
package Day12;
import java.io.IOException;
import java.net.*;
/**
* @ClassName:UDPTest
* @Description: TODO
* @Author ChenS
* @create 2021-06-27-7:35 PM
* @Version 1.0
*/
public class UDPTest {
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
try {
Receiver.receive( 8080);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
Sender.send("String from sender","127.0.0.1",8080);
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
}
class Sender {
public static void send(String str,String senderIP,int port) throws IOException {
//建立UDPSocket
DatagramSocket datagramSocket = new DatagramSocket();
//封装数据包
DatagramPacket datagramPacket = new DatagramPacket(str.getBytes(), 0, str.length(),InetAddress.getByName(senderIP),port);
//发送数据
datagramSocket.send(datagramPacket);
//关闭资源
datagramSocket.close();
}
}
class Receiver{
public static void receive(int port) throws IOException {
//建立UDPSocket
DatagramSocket datagramSocket = new DatagramSocket(port);
//建立接收数据包
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,0,bytes.length);
//接收数据
datagramSocket.receive(datagramPacket);
//使用数据——数据实际上存储到准备的字节数据组中
System.out.println(new String(bytes));
//关闭资源
datagramSocket.close();
}
}
7、URL编程
7-1、概念
- URL:Uniform Resource Locator——统一资源定位符,表示Internet上某一资源的地址
- URL可以用来标识一个资源,还指明了如何locate这个资源
- 通过URL可以访问网络上的各种资源(包括www、ftp),浏览器解析URL可以在网络上查找相应的文件和资源
- URL基本结构的五个组成部分:<传输协议>://<主机名>:<端口号><文件名>#片段名?参数列表
7-1、URL构造器和方法
import java.net.MalformedURLException;
import java.net.URL;
public class URLTest {
public static void main(String[] args) {
//获取URL对象
URL url = null;
try {
url = new URL("https://blog.csdn.net/qq_43810938?spm=1001.2014.3001.5343");
} catch (MalformedURLException e) {
e.printStackTrace();
}
//URL方法
//获取协议名
System.out.println(url.getProtocol());
//获取主机名
System.out.println(url.getHost());
//获取端口号
System.out.println(url.getPort());
//获取文件名
System.out.println(url.getFile());
//获取URL查询名
System.out.println(url.getQuery());
}
}
7-2、借助URL获取服务器资源
import javax.net.ssl.HttpsURLConnection;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
/**
* @ClassName:URLTest
* @Description: TODO
* @Author ChenS
* @create 2021-06-27-8:12 PM
* @Version 1.0
*/
public class URLTest {
public static void main(String[] args) throws IOException {
//获取URL对象
URL url = new URL("https://tsundora.com/image/2016/09/code_geass_600.jpg");
//创建这个ulr的连接对象
HttpsURLConnection urlConnection = (HttpsURLConnection)url.openConnection();
//连接
urlConnection.connect();
//获取输入流,创建输出流
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(new File("code_geass_600.jpg"));
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1){
fileOutputStream.write(bytes, 0, len);
}
//关闭资源
inputStream.close();
fileOutputStream.close();
urlConnection.disconnect();
}
}