Java基础(二十四)——网络编程、InetAddress类、基于 TCP 协议的通信以及相关案例(传输文本、对象、多客户端链接服务端、上传图片)、基于UDP协议的传输
一、网络编程
1、相关概念
1.计算机网络:将不同地区的电脑 使用网络进行连接 从而实现数据的交互与共享
2.网络编程三要素:IP地址 端口号 协议
3.IP地址:IP地址是计算机在网络中的唯一的标识
4.IP分类:IP4与IP6
IP4:192.168.1.130 10.3.138.115 子网
IP4是有4个字节的二进制组成 记忆比较麻烦 目前都是十进制表示形式
IP6是由十六进制组成的
5.查看IP
第一步 windons+r
第二步 输入cmd
第三步输入 ipconfig
6.检查服务器是否连接成功 ping +IP地址
7.端口号:端口是进程在计算机中唯一的标识 端口号范围 0-65535 1-1024(一般是系统的端口号 不建议使用)
8.常用的端口号:
mysql:3306
qq:4000
oralce:1521
tomcat:8080
2、协议
1.协议:网络传输数据的规则 必须遵循这个规则才能进行数据的交互。
2.常见的协议:
TCP:面向连接的协议,三次握手,传输效率低,不会出现丢失数据 丢包。
UDP:面向无连接的协议,传输的效率高,会丢失数据(短信群发)。
HTTP:一次性连接协议,客户端与服务器交互成功就断开,大部分的web项目的都是使用HTTP协议,效率快,
安全性高,HTTP传输的数据的时候没有对数据进行加密。
HTTPS = HTTP+SSL。SL证书传输数据的时候会对数据进行加密传输 保证数据的安全性。
二、InetAddress 类
此类表示互联网协议 (IP) 地址 UDP 和 TCP 协议都是在它的基础上构建的。
下面是方法的使用:
三、基于 TCP 协议的通信
.此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点。
1、常用方法
构造方法:
2、案例(一)——传输简单的文本
既然是通信,就需要两个端来互相说话,一般分为服务端跟客户端。
客户端代码:
public class Demo1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost",8899); // 实例化 Socket 。localhost:表示本机IP地址。也可以手动填数字。
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream(); // 获得输入流和输出流
String str = "屌你老母"; // 要传输的文本
os.write(str.getBytes(),0,str.getBytes().length); // 写入文字,并传输过去
socket.shutdownOutput(); // 刷新缓冲区
BufferedReader br = new BufferedReader(new InputStreamReader(is)); // 实例化对象。接收服务端发来的文本。字节流转换为字符流
String str2 = null;
while ((str2 = br.readLine()) != null){
System.out.println(str2);
}
os.close(); // 关流。顺序是从最近使用过的开始,一级一级往上关。
is.close();
socket.close();
}
}
服务端代码:
public class Ser1 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999); // 实例化ServerSocket。客户端与服务端的端口号必须是同一个。
Socket socket = serverSocket.accept(); // 开启监听。如果有客户端发来消息就接听
InputStream is = socket.getInputStream(); // 实例化输入输出流
OutputStream os = socket.getOutputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is)); // 接收客户端发来的文本。字节流转换为字符流
String str = null;
while ((str = br.readLine()) != null){
System.out.println(str);
}
String str2 = "神经病";
os.write(str2.getBytes(),0,str2.getBytes().length); // 把文本发送回客户端
socket.shutdownOutput(); // 刷新缓冲区
br.close(); // 自最近使用过的,一级一级往上关
os.close();
is.close();
socket.close();
serverSocket.close();
}
}
3、案例(二)——传输对象
代码大同小异,无非就是对象流的输出读取罢了。注意的是,创建对象的类要序列化。看代码:
客户端:
public class Demo1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost",9999);
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
Person p1 = new Person("zs", 18);
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(p1);
}
}
服务端:
public class Ser1 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
ObjectInputStream ois = new ObjectInputStream(is);
Person p1 =(Person) ois.readObject();
System.out.println(p1);
}
}
4、案例(三)——多客户端与服务器进行交互——多线程解决方案
前面的都是一个客户端与一个服务端相连接。如果是两个客户端甚至是多个客户端相连接呢?如果还是原来的代码,则会报错,原因是因为服务端那仅有的一条连接被占用了,如果有更多的链接进来,则链接不了,所以解决方案是服务端开启多线程:
客户端的代码不需要动。主要是服务端的代码还有开启多线程的代码:
多线程的代码(基本还是服务端的代码):
public class MyThread_Service extends Thread {
private Socket socket; // 私有化
public MyThread_Service(Socket socket) { // 构造方法。把外面的 socket 对象传递到这里面。
this.socket = socket;
}
@Override
public void run() {
try {
InputStream is = socket.getInputStream();
OutputStream os = socket.getOutputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String str = null;
while ((str = br.readLine()) != null){
System.out.println(str);
}
String str2 = "神经病";
os.write(str2.getBytes(),0,str2.getBytes().length);
socket.shutdownOutput();
br.close();
os.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
然后就是服务端的代码:
public class Ser1 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
while (true){
Socket socket = serverSocket.accept(); // 监听。
MyThread_Service thread = new MyThread_Service(socket); // 实例化线程对象。注意,多线程那边的有参构造方法。
thread.start(); // 开启多线程
}
}
}
5、案例(四)——图片上传
代码跟以前 IO 流的大差不差:
客户端代码:
public class Demo1 {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("localhost",9999);
InputStream is = new FileInputStream("1.jpg"); // 读取图片
OutputStream os = socket.getOutputStream(); // 实例化输出流。为后续传输图片做好准备
byte[] b = new byte[1024]; // 定义一个缓冲区的数组进行读操作
int len;
while ((len = is.read(b)) != -1){
os.write(b,0,len ); // 写。图片传输
}
socket.shutdownOutput(); // 刷新输出流
socket.close();
os.close();
is.close();
}
}
服务端代码:
public class Ser1 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream(); // 实例化输入流对象
File f = new File("D:\\"); // 定义好文件路径。准备把图片保存到这个目录
if (!f.exists()){ // 如果这个路径的目录不存在,则创建。包括多层父目录
f.mkdirs();
}
long time = System.currentTimeMillis(); // 获取系统当前时间(精确到毫秒)
String FileName = time+".jpg"; // 以当前时间命名文件名字(防止上传的图片重名,重名会覆盖文件)
OutputStream os = new FileOutputStream(new File(f, FileName)); // 实例化输出流。
byte[] b = new byte[1024];
int len;
while ((len = is.read(b)) != -1){
os.write(b, 0, len); // 把图片储存到相关路径
}
os.close();
is.close();
socket.close();
serverSocket.close();
}
}
四、基于UDP协议传输
此类表示用来发送和接收数据报包的套接字。
UDP:面向无连接的协议,传输的效率高,会丢失数据(短信群发)。
1、构造方法
2、常用方法
3、案例(一)——传输简单的文本
客户端代码:
public class Demo1 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(); // 实例化
String str = "这里是客户端,你呢"; // 传输文本
byte[] b = str.getBytes();
InetAddress address = InetAddress.getByName("localhost"); // 获取本机的IP地址
DatagramPacket dp = new DatagramPacket(b, 0,b.length,address,9999); // 创建一个包裹对象。(参数就不说明了,跟前面 IO 流和 TCP 的差不多。
socket.send(dp); // 发送
}
}
服务端:
public class Ser1 {
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(9999); // 实例化对象。
byte[] b = new byte[1024];
DatagramPacket dp = new DatagramPacket(b,0,b.length); // 构建一个空的包裹
socket.receive(dp); // 接收包裹并把里面的数据存到包裹对象当中
System.out.println(new String(dp.getData(),0,dp.getData().length)); // 打印数据
}
}