Java基础Day24

day24

  1. 网络编程概述
    1.1 网络编程的概念
    计算机网络: 指在不同的地理位置上,具有独立运行功能的计算机设备,使用通讯的连接,形成了一个计算机的系统,实现计算设备之间的数据通讯和数据的共享
    网络编程: 在具有稳定的网路系统的情况下,实现计算设备之间的数据通讯

1.2 网络编程三要素
网络编程中具有的三要素 : 1. IP地址 2. 端口号 3. 通讯协议

1.2.1 IP地址

  1. IP地址 : 计算机的网络中,每一台计算机的唯一标识. 就好比人类的身份证
  2. IP地址的分类:
    1)IPv4: 目前多数的网路编程使用,都是使用IPv4
    每一个IP地址,有4个段位,每个段位使用8个2进制进行表示
    10.10.116.60---->IP地址

8个2进制位: 11111111---->将2进制转化成10进制------>最大值255
世界上的IPv4地址 : 000.000.000.000----->255.255.255.255

IPv4 一共可以表示大概42亿的IP, 目前情况IPv4地址不够用,扩展,于是引入了IPv6

  1. IPv6: 8段位,每个段位中,都是4位的16进制
    IPv6 号称让世界上每一粒沙子都是具有一个IP地址
  1. 查看本机的ip地址的命令
    打开dos窗口---->输入命令 ipconfig
    在这里插入图片描述

  2. dos中查看对方ip是否可以连接或者是访问
    ping + IP地址,IPv4
    在这里插入图片描述

  3. 本机回环地址 : 127.0.0.1 ,这个地址就表示你所在的计算机的IP地址,
    127.0.0.1理解方式 : 中文中,汉字我, 我怎么使用,哪个人使用了我,这个我就代表哪个人

1.2.2 端口号

  1. 端口号 : 表示计算机设备中, 应用程序在计算机中的唯一标识

  2. 端口号如何生成:
    操作系统会给在内存中运行的应用程序设置一个端口号,端口号的分配有时是随机的,有时也是固定, 有一些使用率非常高的应用,就会有固定的端口号 ; 一些应用程序临时或者是使用概率不是特别高,每次使用系统随机的分配端口号

  3. 端口号的使用范围
    端口号占有2个字节,连续的16个2进制位,1111 1111 1111 1111
    范围 0-65535, 计算设备中最多能同时支持65536个程序运行

  4. 常用应用的端口号
    QQ 4000
    mysql 3306
    tomcat 8080
    web 80

注意 : 1024以下的端口进行不要使用,原因是操作系统底层中很多应用程序使用0-1024之间的端口,避免发生端口冲突

在这里插入图片描述

1.2.3 通讯协议
通讯协议 : 表示计算机设备在进行数据的通讯的时候,需要准守的规则
规则包括 : 数据的封装和数据的解析,以及数据在传输过程中精确性

好比 : 交通法规,所有人准守的法规是一致的,因此开车在路上才是安全的

通讯协议中 : 目前使用最多的TCP/IP协议

1.3 InetAddress类
InetAddress类,来自于java.net包,表示计算机的主机名+ip地址的类型
InetAddress中没有提供出公共的构造方法,因此不能直接创建对象,可以通过类中的静态方法,创建出InetAddress对象出来

静态方法: 获取到InetAddress类对象

  1. getLocalHost() : 表示返回当前计算设备的主机名+ip地址这样的一个InetAddress类对象
  2. getByName(String host) : 通过主机名host或者ip地址获取到对应的InetAddress类对象
  3. getByAddress(byte[] addr) : 将IP地址使用数组的方式作为参数,返回一个InetAddress类对象
  4. getByAddress(String host, byte[] addr) : 提供host主机名+addrip地址的数组,返回一个InetAddress类对象

常用非静态方法:

  1. getHostName(): :获取主机名,返回值类型String类型
  2. getHostAddress() : 获取到IP地址,返回值类型String类型
  3. toString() : 将一个InetAddress对象结果转换成字符串,返回值类型字符串

代码
package com.zgjy.address;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
// 创建一InetAddress对象
// 1. getLocalHost() : 表示返回当前计算设备的主机名+ip地址这样的一个InetAddress类对象
InetAddress ia = InetAddress.getLocalHost();
System.out.println(ia);// pc/10.10.116.60
// 5. getHostName() :获取主机名,返回值类型String类型
// getHostAddress() : 获取到IP地址,返回值类型String类型
String name = ia.getHostName();
String ip = ia.getHostAddress();
// pc—10.10.116.60
System.out.println(name + “—” + ip);

	// 6. toString() : 将一个InetAddress对象结果转换成字符串,返回值类型字符串
	String address = ia.toString();
	//-----------pc/10.10.116.60
	System.out.println("-----------"+address);
	
	// 2.getByName(String host) : 通过主机名host获取到对应的InetAddress类对象
	InetAddress ia1 = InetAddress.getByName("pc");
	System.out.println(ia1);//pc/10.10.116.60
	
	InetAddress ia2 = InetAddress.getByName("10.10.116.60");
	System.out.println(ia2);//  /10.10.116.60
	
	// 3. getByAddress(byte[] addr) : 将IP地址使用数组的方式作为参数,返回一个InetAddress类对象
	byte[] b = {10,10,116,60};	
	InetAddress ia3 = InetAddress.getByAddress(b);
	System.out.println(ia3);//  /10.10.116.60
	
	// 4. getByAddress(String host, byte[] addr) : 提供host主机名+addrip地址的数组,返回一个InetAddress类对象
	InetAddress ia4 = InetAddress.getByAddress("pc", b);
	System.out.println(ia4);// pc/10.10.116.60
}

}

1.4 Socket套接字编程
Socket 类: 就叫做套接字,表示端(计算机)到端的通讯,看成码头,快递车,可以进行计算设备之间的数据传输

UDP套接字编程 : DatagramPacket DatagramSocket
TCP套接字编程 Server ServerSocket

1.5 UDP协议 与 TCP协议的区别
UDP 协议: 面向无连接, UDP分为发送端(主要进行数据发送)和接收端(进行数据的接收和解析),发送端向接收端发送数据时,接收端可以不存在
举例,发微信,发短信, 你的发送与接收端是否存在不发生直接的关系

特点:
UDP安全性低,速度快, 不保证数据的安全性,数据在传输的过程中有可能确实,一般大数据以及精确传输不使用UDP,UDP传输的数据大小,一次,不能超过64KB

TCP : 面向有连接, 分别服务器端和客户端,一般都是客户端向服务器端发送请求,请求连接,如果服务器端不存在,就会报错,客户端就不能发送数据
举例 : 打电话, 王者荣耀

特点:
TCP协议传输速度相对较慢,安全性高,能保证数据的安全性,数据的发送和接收完全一致,TCP协议在进行数据传输是,可以传输大型文件

  1. UDP编程
    UDP面向无连接编程: 比拟成邮寄快递的过程
    DatagramPacket: 来自于java.net包,表示数据报包,就是进行数据的封装和解析
    数据封装 : 发送端发送数据时,需要将数据打包(封装)
    数据解析 : 接收端在接收到数据后,将数据获取到(解析)
    快递包裹

DatagramSocket: 来自于java.net,表示数据的发送和接收
数据发送 : 发送端将数据发送到接收端
数据接收 : 接收端获取数据
快递车

2.1 UDP的发送端
UDP发送端的实现步骤:

  1. 准备需要发送的数据,数据的类型是字节数组类型,因为DatagramPacket中可以封装的数据类型只有字节数组
  2. 将准备好的数据byte[] ,放置到DatagramPacket中
    使用DatagramPacket构造方法:
    DatagramPacket(byte[] buf, int length, InetAddress address, int port)
  1. buf参数是一个字节数组,表示需要发送的数据
  2. length,表示将数组的多少字节进行发送
  3. address,表示要将数据发送到哪里(对方的IP)
  4. port ,表示目标计算机的端口号
  1. 使用DatagramSocket进行数据的发送
  1. 构造方法使用空参数构造即可
  2. 数据发送,使用send(DatagramPacket p) : 表示将数据p发送到指定的ip和端口上
  1. 关闭资源,使用close(); 方法

代码
package com.zgjy.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

//UDP的发送端
public class UDPSend {
public static void main(String[] args) throws IOException {
// 1. 准备要发送的数据,字节数组
byte[] b = “你好,UDP”.getBytes();
// 2. 将数据进行封装,封装到DatagramPacket中
DatagramPacket dp = new DatagramPacket(b, b.length, InetAddress.getByName(“127.0.0.1”), 8888);
// 3. 创建一个DatagramSocket对象,用于数据的发送
DatagramSocket ds = new DatagramSocket();
// 4. 调用send方法,将封装好的数据,发送到指定的IP和端口号上
ds.send(dp);
// 5.关闭资源
ds.close();
}
}

2.2 UDP的接收端
UDP接收端的实现步骤:

  1. 需要将接收数据的端口号,先进行监听(打开,使用)
    使用DatagramSocket的构造方法
    DatagramSocket(int port): 表示开启port对应的端口号,准备进行数据的通讯
  2. 准备DatagramPacket,用于承装发送端的数据
    DatagramPacket(byte[] buf, int length) : 将发送端的数据,接收到buf数组中
  3. 接收数据
    DatagramSocket中的receive(DatagramPacket p):将发送端的数据接收到,然后将接收到的数据传递到DatagramPacket 中
  4. 从DatagramPacket 中解析数据
  1. getLength() : 返回接收或者是发送时的数据长度
  2. getPort() : 获取到发送发的端口号,了解即可
  3. getAddress() : 获取到发送方的IP地址
  1. 关闭资源

代码
package com.zgjy.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UDPReceive {
public static void main(String[] args) throws IOException{
// 1. 打开8888端口,准备接收数据
DatagramSocket ds = new DatagramSocket(8888);
// 2.创建一个DatagramPacket对象,用于承装发送端的数据
byte[] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b, b.length);
// 3. 接收数据,DatagramSocket中的receive(DatagramPacket dp)方法
// receive方法具有阻塞的功能: 等待发送端发送数据后,才能继续运行
System.out.println(“等到接收数据”);
ds.receive(dp);
System.out.println(“接收数据成功”);
// 4. 数据的解析
// 1) 获取到接收到的数据长度 getLength()
int length = dp.getLength();
// 2) 获取到对方的Ip地址getAddress()
// 3)getPort() : 获取到发送方的端口号
System.out.println(dp.getAddress()+":"+dp.getPort() + new String(b,0,length));
// 5. 关闭资源
ds.close();
}
}

2.3永不停歇的聊天工具
要求 : 设计出一个可以一直聊天的工具,发送端从键盘录入,一直向接收端进行数据的发送
思路 : 将发送端和接收端设计在死循环中

多个程序运行,控制台的查看
在这里插入图片描述

代码
package com.zgjy.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

//改造成永不停歇的键盘录入发送端
public class UDPNeverStopSend {
public static void main(String[] args) throws IOException {
// 1. 准备要发送的数据,字节数组
Scanner sc = new Scanner(System.in);
// 2. 创建一个DatagramSocket对象,用于数据的发送
DatagramSocket ds = new DatagramSocket();
while(true) {
// 键盘录入要发送的数据
String s = sc.next();
byte[] b = s.getBytes();
// 3. 将数据进行封装,封装到DatagramPacket中
DatagramPacket dp = new DatagramPacket(b, b.length, InetAddress.getByName(“127.0.0.1”), 8888);
// 4. 调用send方法,将封装好的数据,发送到指定的IP和端口号上
ds.send(dp);
}
// 5.关闭资源
//ds.close();
}
}

package com.zgjy.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
// UDP的永不停歇的接收端
public class UDPReceiveAlways {
public static void main(String[] args) throws IOException{
// 1. 打开8888端口,准备接收数据
DatagramSocket ds = new DatagramSocket(8888);
// 2.创建一个DatagramPacket对象,用于承装发送端的数据
byte[] b = new byte[1024];
while(true) {
DatagramPacket dp = new DatagramPacket(b, b.length);
// 3. 接收数据,DatagramSocket中的receive(DatagramPacket dp)方法
// receive方法具有阻塞的功能: 等待发送端发送数据后,才能继续运行
ds.receive(dp);
// 4. 数据的解析
// 1) 获取到接收到的数据长度 getLength()
int length = dp.getLength();
// 2) 获取到对方的Ip地址getAddress()
// 3)getPort() : 获取到发送方的端口号
System.out.println(dp.getAddress()+":"+dp.getPort() + new String(b,0,length));
}
// 5. 关闭资源
//ds.close();
}
}

  1. TCP编程
    TCP编程,面向有连接,分为:
    客户端 : Socket
    服务器端 : ServerSocket

举例: 游戏,英雄联盟,本地计算中的都是下载的客户端,远程的服务器端
TCP中,一般情况下,都是客户端主动的连接服务器端

在这里插入图片描述

3.1 TCP的客户端
主要是用Socket类
Socket类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。

TCP客户端的实现步骤:

  1. 创建一个客户端的Socket对象,
    使用构造方法 : Socket(String address , int port) : 表示连接address的ip地址
    注意 : 如果ip地址不在,那么客户端直接报错
  2. 使用流资源进行与服务器的数据传输
  1. 向服务器发送数据,需要写,需要输出,需要输出流
  2. Socket中的方法 : getOutputStream() : 获取到一个输出流,返回值类型OutputStream字节输出流,使用write向服务器写内容
  3. Socket中的方法 : getInputStream() : 获取到一个输入流,返回值类型InputStream字节输入流,用于读取服务器返回的响应,使用read方法读
  1. close() : 关闭Socket套接字的资源

代码
package com.zgjy.tcp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class TCPSocket {
public static void main(String[] args) throws IOException{
// 1. 创建一个Socket客户端对象
// 含义 : 进行服务器的指定端口的连接
// 说明 : 如果服务器不在,那么客户端在尝试连接服务器时,就会报错
Socket s = new Socket(“127.0.0.1”, 9999);
// 2. 获取到字节输出流,用于向服务器写入数据
// getOutputStream()方法实际返回值为OutputStream抽象类的一个子类
OutputStream os = s.getOutputStream();
// 3. 使用write向服务器写内容
os.write(“在吗?服务器”.getBytes());
// 4. 接收服务器给的响应,获取对应的字节输入流(读取服务器响应的数据)
InputStream is = s.getInputStream();
byte[] b = new byte[1024];
is.read(b);
System.out.println(new String(b));
// 5. 关闭套接字资源
s.close();
}
}

3.2 TCP的服务器端
主要使用ServerSocket类
在这里插入图片描述

TCP的服务器端的实现步骤:

  1. 需要先将服务器的端口监听
    ServerSocket的构造方法: ServerSocket(int port) : 表示将服务器的指定端口打开
  2. 接收客户端发送的请求数据
  1. 先通过ServerSocket中的accept() 方法获取到客户端你的套接字对象
  2. 使用客户端的套接字获取到对应的输入流
  1. 向客户端发送响应
    使用使用客户端的套接字获取到对应的输出流,向客户端写入数据
  2. 关闭资源

代码
package com.zgjy.tcp;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServerSocket {
public static void main(String[] args) throws IOException{
// 1. 创建一个服务器端的对象,绑定端口,进行端口监听
ServerSocket ss = new ServerSocket(9999);
// 2. 通过ServerSocket中的accept() 方法获取到客户端你的套接字对象
// 注意 : accept方法具有阻塞功能,等待客户端发送请求才继续执行
System.out.println(“等待客户端请求”);
Socket s = ss.accept();
System.out.println(“收到客户端请求”);
// 3. 通过套接字对象s,获取到输入流,读取客户端发送的请求数据
InputStream is = s.getInputStream();
byte[] b = new byte[1024];
is.read(b);
// 4. 查看客户端发送的信息
System.out.println(new String(b));

	// 5. 向客户端返回一个响应
	// 需要向客户端写数据,需要一个输出流
	// 从套接字对象s中获取输出流
	OutputStream os = s.getOutputStream();
	os.write("收到,可以连接!".getBytes());
	
	// 6. 关闭资源
	ss.close();
}

}

3.3 客户端向服务器端上传图片
要求 : 从客户端所在计算机的某个路径下读取一张图片,上传到服务器的D:\download路径下,复制图片的名字为b.jpg ,服务器端给客户端响应,上传成功

分析:
在这里插入图片描述

客户端代码
package com.zgjy.tcp;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class TCPSendPicture {
// 客户端 : Socket 类 , 向服务器上传图片
public static void main(String[] args) throws IOException{
// 1. 创建一个Socket对象,先绑定服务器的Ip和端口号
Socket s = new Socket(“127.0.0.1”, 8899);
OutputStream os = s.getOutputStream();
// 2. 向服务器上传数据,数据是一个图片
// 1) 先获取到图片数据,D:\0826Java系统班\day01\图解\Java跨平台性.png
FileInputStream fis = new FileInputStream(“D:\0826Java系统班\day01\图解\Java跨平台性.png”);
// 3. 使用字节数组的方式进行图片的读取
byte[] b = new byte[1024];
int len ;// 表示每次读到的字节数
while((len = fis.read(b)) != -1) {
// 4. 写入到客户端,相当于向服务器传递数据
os.write(b, 0, len);
}
// 注意: 出了while循环后,证明图片内容已经上传完毕,于是需要给服务器一个提示
// 输出流已经结束,服务器不需要在等待读取内容了
s.shutdownOutput();

	// 4. 接收服务器端的反馈,读
	InputStream is = s.getInputStream();
	// 将从服务器读到的数据放置到数组b中
	len = is.read(b);
	// 5. 将反馈结果进行输出
	System.out.println(new String(b,0,len));
	
	// 6. 关闭资源
	fis.close();
	s.close();	
}

}

服务器端代码
package com.zgjy.tcp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPReceivePicture {
// 服务器端接收图片,上传到本地的D:\download\b.jpg
public static void main(String[] args) throws IOException{
// 1. 打开8899端口,进行数据监听
ServerSocket ss = new ServerSocket(8899);
// 2. 接口客户端传递的图片数据,使用流资源,来自于客户端与服务器端之间的流
// 1) 使用accept获取到客户端的套接字对象
// 2) 使用套接字对象获取输入流,读取客户端传递的数据
Socket s = ss.accept();
InputStream is = s.getInputStream();
// 3. 保证上传的文件所在的文件夹一定存在
File f = new File(“D:\download”);
if( !f.exists()) {// 判断文件夹路径是否存在,不存在新建
f.mkdirs();
}

	// 4. 创建一个字节的输出流,用于向磁盘中写入图片内容
	FileOutputStream fos = new FileOutputStream(f + "\\b.jpg");
	
	// 5. 循环读取客户端上传的图片,通过数组的方式读取
	byte[] b = new byte[1024];
	int len;
	System.out.println("开始接收图片");
	while((len = is.read(b)) != -1) {
		// 4.复制到D:\\download\\b.jpg
		// 写入到磁盘的文件,需要一个输出流,于是使用字节输出流
		// 与磁盘交互,自己创建字节输出流
		fos.write(b, 0, len);
	}
	System.out.println("接收图片完成");
	
	//6. 给客户端一个响应,是客户端与服务器端之间的数据交互
	OutputStream os = s.getOutputStream();
	os.write("上传成功".getBytes());
	
	// 7. 关闭资源
	fos.close();
	ss.close();	
}

}

注意 : 代码运行过程中,出现了图片复制成功,但是代码没有结束的问题
问题发生原因及解决方案:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值