• day41-网络编程03


    Java网络编程03

    5.UDP网络通信编程[了解]

    5.1基本介绍

    1. DatagramSocket DatagramPacket[数据报/数据包]实现了基于 UDP的协议网络程序
    2. UDP数据报通过数据报套接字DatagramSocket 发送和接收,系统不保证UDP数据报一定能够安全的送到目的地,也不确定什么时候可以抵达
    3. DatagramPacket 对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号,以及接收端的IP地址和端口号
    4. UDP协议中每个数据报都给出了完整的的地址信息,因此无需建立发送方和接收方的连接

    image-20220919170633135

    UDP说明:

    • 没有明确的服务端可客户端,演变成数据的发送端和接收端
    • 接收数据和发送数据是通过DatagramSocket 对象完成的
    • 将数据封装到DatagramPacket 对象(装包)发送
    • 当接收到DatagramPacket 对象,需要进行拆包,取出数据
    • DatagramSocket 可以指定在某个端口接收数据

    5.2基本流程和应用案例

    1. 核心的两个类/对象 DatagramSocket 与 DatagramPacket
    2. 建立发送端和接收端(没有服务端和客户端的概念)
    3. 建立数据报/包-DatagramPacket
    4. 调用DatagramSocket的发送、接收方法
    5. 关闭DatagramSocket
    image-20220919171111390

    应用案例1:

    1. 编写一个接收端A和一个发送端B
    2. 接收端A在9999端口等待接收数据(receive)
    3. 发送端B向接收端A 发送数据 “hello,明天吃火锅~”
    4. 接收端A收到后,回复“好的,明天见”,然后退出
    5. 发送端B接收回复的信息,再退出
    image-20220919171911656

    接收端UDPReceiverA:

    package li.network.udp;
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    //UDP接收端A
    public class UDPReceiverA {
    public static void main(String[] args) throws IOException {
    // 1.创建一个DatagramSocket对象,准备在9999端口 接收 数据
    DatagramSocket datagramSocket = new DatagramSocket(9999);
    // 2.构建一个DatagramPacket对象,准备接收数据
    //因为UDP的每个数据报限制在64k内
    byte[] buf = new byte[1024];
    DatagramPacket packet = new DatagramPacket(buf, buf.length);
    //3. 调用接收方法,将通过网络传输的 DatagramPacket对象
    // 填充到 packet对象中
    // 当有数据报发送到本机的9999端口时,就会接收到数据
    // 如果没有数据报发送到本机的 9999端口,就会阻塞等待
    System.out.println("接收端A 等待接收数据...");
    datagramSocket.receive(packet);
    //4.把 packet进行拆包,取出数据,并显示
    int length = packet.getLength();//实际接收到的数据长度
    byte[] data = packet.getData();//实际接收到的数据
    String s = new String(data, 0, length);//构建字符串
    System.out.println(s);
    //5. (发送)回复消息===
    //bytes, bytes.length, InetAddress.getByName("192.168.1.6"), 8888
    //分别对应 发送的内容 内容长度 对方的ip 对发的接收端口
    byte[] bytes = "好的 明天见".getBytes();
    DatagramPacket datagramPacket =
    new DatagramPacket(bytes, bytes.length, InetAddress.getByName("192.168.1.6"), 8888);
    datagramSocket.send(datagramPacket);
    //6.关闭资源
    datagramSocket.close();
    System.out.println("A端 退出");
    }
    }

    发送端UDPSenderB:

    package li.network.udp;
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    //发送端B====>也可以接收数据
    public class UDPSenderB {
    public static void main(String[] args) throws IOException {
    //1.创建DatagramSocket ,准备在8888端口接收数据
    //这里的端口是为了接收A回复的数据
    DatagramSocket datagramSocket = new DatagramSocket(8888);
    //2.将需要发送的数据封装到 DatagramPacket对象
    byte[] data = "hello 明天吃火锅".getBytes();
    //说明封装的对象:
    // data- 内容字节数组
    // data.length- 字节数组的长度
    // 主机(IP)-接收方的ip
    // 9999 -对方用来接收数据的端口
    DatagramPacket datagramPacket =
    new DatagramPacket(data, data.length, InetAddress.getByName("192.168.1.6"), 9999);
    datagramSocket.send(datagramPacket);
    //3.(接收)接收回信===
    //3.1构建一个DatagramPacket对象,准备接收数据
    byte[] buf = new byte[1024];
    DatagramPacket packet = new DatagramPacket(buf, buf.length);
    //3.2调用receive接收方法,将通过网络传输的 DatagramPacket对象
    // 填充到 packet对象中
    // 当有数据报发送到本机的8888端口时,就会接收到数据
    // 如果没有数据报发送到本机的 8888端口,就会阻塞等待
    datagramSocket.receive(packet);
    //拆包
    int length = packet.getLength();//实际接收到的数据长度
    byte[] bytes = packet.getData();//实际接收到的数据
    String s = new String(bytes, 0, length);//构建字符串
    System.out.println(s);
    //4.关闭资源
    datagramSocket.close();
    System.out.println("B端 退出");
    }
    }

    先启动接收端A:

    image-20220919175355053

    启动发送端B之后:

    image-20220919175635455 image-20220919181029782

    6.本章作业

    6.1Homework01

    1. 使用字符流的方式,编写一个客户端程序和服务端程序
    2. 客户端程序发送“name”,服务端接收到后,返回“nova”
    3. 客户端发送“hobby”,服务端接收到后,返回 “打代码”
    4. 若客户端发送的是其他信息,则服务端回复“你说啥呢?”
    5. 可以循环问答

    服务端Homework01Server:

    package li.network.homework.homework01;
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    public class Homework01Server {
    public static void main(String[] args) throws IOException {
    //1.服务端 在9999端口等待连接...
    ServerSocket serverSocket = new ServerSocket(9999);
    System.out.println("服务端:正在9999端口等待连接...");
    Socket socket = serverSocket.accept();
    BufferedReader br = null;
    BufferedWriter bw = null;
    int loop = 999;
    while ((loop--) != 0) {
    //2.服务端接收数据
    br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String s = br.readLine();
    System.out.println(s);
    //3.服务端发送数据
    bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    if (s.equals("来自客户端:你的名字?")) {
    bw.write("来自服务端:我是jack");
    } else if (s.equals("来自客户端:你的爱好?")) {
    bw.write("来自服务端:打代码");
    } else {
    bw.write("来自服务端:你在说啥??");
    }
    bw.newLine();//写入结束标志
    bw.flush();
    }
    //4. 关闭流和socket
    br.close();
    bw.close();
    socket.close();
    serverSocket.close();
    System.out.println("服务端退出..");
    }
    }

    客户端Homework01Client:

    package li.network.homework.homework01;
    import java.io.*;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.util.Scanner;
    public class Homework01Client {
    public static void main(String[] args) throws IOException {
    //1.客户端连接服务端
    //InetAddress.getByName("192.168.1.6"),9999
    // --服务端ip和服务端的端口
    Socket socket = new Socket(InetAddress.getByName("192.168.1.6"), 9999);
    BufferedReader br = null;
    BufferedWriter bw = null;
    int loop = 999;
    while ((loop--) != 0) {
    //2.客户端发送数据
    //从键盘读取用户问题
    Scanner scanner = new Scanner(System.in);
    System.out.println("请输入你的问题:");
    String question = scanner.next();
    //数据 写入 数据通道
    bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    bw.write("来自客户端:" + question);
    bw.newLine();//结束写入标志
    bw.flush();
    //3.客户端接收数据
    br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
    String s = br.readLine();
    System.out.println(s);
    }
    //4.关闭流和socket
    bw.close();
    br.close();
    socket.close();
    System.out.println("客户端退出..");
    }
    }

    image-20220919191111928 image-20220919191132296

    6.2Homework02

    1. 编写一个接收端A和一个发送端B,使用UDP协议完成
    2. 接收端在8888端口等待接收数据(receive)
    3. 发送端向接收端 发送数据 “四大名著是哪些?”
    4. 接收在接收到 问题后,返回答案“《红楼梦》《三国演义》.... ”,否则就返回 ”what?“
    5. 接收端和发送端退出
    6. 最好可以循环问答

    思路:

    image-20220919203011555

    接收端Homework02ReceiverA:

    package li.network.homework;
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    //接收端A
    public class Homework02ReceiverA {
    public static void main(String[] args) throws IOException {
    //1.创建DatagramSocket对象,指定端口
    // 9999:指定 接收数据的端口
    DatagramSocket datagramSocket = new DatagramSocket(8888);
    System.out.println("接收端A 等待接收数据...");
    int loop = 999;
    while ((loop--) != 0) {
    //2.接收信息
    //2.1构建一个DatagramPacket对象,用来装入接收到的 DatagramPacket
    byte[] buf = new byte[1024];
    DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
    //2.2使用receive接收数据
    datagramSocket.receive(datagramPacket);
    //2.3取出内容--拆包
    byte[] data = datagramPacket.getData();//真正接收到的内容
    int length = datagramPacket.getLength();//内容的长度,用于构建字符串
    String s = new String(data, 0, length);//构建字符串
    System.out.println(s);
    //3.发送回信
    byte[] databack = null;
    if (s.equals("四大名著是那些?")) {
    //封装要发送的信息,放到DatagramPacket对象中
    databack = "红楼梦、三国演义、水浒传、西游记".getBytes();
    } else {
    databack = "what???".getBytes();
    }
    //在DatagramPacket对象指明发送的内容、长度、接收方的ip地址、接收方的端口
    DatagramPacket datagramPacket2 =
    new DatagramPacket(databack, databack.length, InetAddress.getByName("192.168.1.6"), 9999);
    datagramSocket.send(datagramPacket2);
    }
    //4.关闭sock
    datagramSocket.close();
    System.out.println("接收端A 退出");
    }
    }

    发送端Homework02SenderB:

    package li.network.homework;
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.util.Scanner;
    //发送端B
    public class Homework02SenderB {
    public static void main(String[] args) throws IOException {
    //1.创建DatagramSocket ,准备在8888端口接收数据
    //这里的端口是为了接收A回复的数据
    DatagramSocket datagramSocket = new DatagramSocket(9999);
    int loop = 999;
    while ((loop--) != 0) {
    //2.发送数据
    //2.1从键盘获取问题
    Scanner scanner = new Scanner(System.in);
    System.out.println("请输入你的问题:");
    String question = scanner.next();
    //2.2将需要发送的数据封装到 DatagramPacket对象
    //在DatagramPacket对象指明发送的内容、长度、接收方的ip地址、接收方的端口
    byte[] data = question.getBytes();
    DatagramPacket datagramPacket =
    new DatagramPacket(data, data.length, InetAddress.getByName("192.168.1.6"), 8888);
    datagramSocket.send(datagramPacket);
    //3.接收数据
    //3.1先构建一个DatagramPacket对象,用来装入接收到的 DatagramPacket
    byte[] buf = new byte[1024];
    DatagramPacket datagramPacket2 = new DatagramPacket(buf, buf.length);
    //3.2取出内容--拆包
    datagramSocket.receive(datagramPacket2);
    byte[] data2 = datagramPacket2.getData();//接收到的真正内容
    int length = datagramPacket2.getLength();//内容的长度
    String s = new String(data2, 0, length);
    System.out.println(s);
    }
    //4.关闭socket
    datagramSocket.close();
    System.out.println("发送端B 退出");
    }
    }

    image-20220919201921089 image-20220919201948559

    6.3Homework03

    1. 编写一个客户端程序和服务端程序
    2. 客户端可以输入一个 音乐文件名,比如高山流水, 服务端收到音乐名后,可以给客户端返回这个音乐文件,如果服务器没有这个文件,则返回一个默认的音乐即可
    3. 客户端收到文件后,保存到本地d盘
    4. 提示:该客户端可以使用StreamUtils.java

    本质:其实就是指定下载文件的应用

    思路:

    image-20220919232143727

    服务端Homework03Server:

    package li.network.homework;
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    //服务端
    public class Homework03Server {
    public static void main(String[] args) throws IOException {
    //1.设置服务器监听端口,等待客户端连接
    ServerSocket serverSocket = new ServerSocket(9999);
    //2.等待连接
    System.out.println("服务端等待连接...");
    Socket socket = serverSocket.accept();
    //3.读取数据--读取文件名
    InputStream inputStream = socket.getInputStream();
    //3.1将获取的文件名放入字节数组中
    byte[] bytes = new byte[1024];
    int len = 0;
    String downLoadFileName = "";
    while ((len = inputStream.read(bytes)) != -1) {
    downLoadFileName += new String(bytes, 0, len);//拼接得到文件名
    }
    System.out.println("客户端希望下载的文件名称=" + downLoadFileName);
    //4.对文件名进行比较
    String srcFilePath = "d:\\Server\\";
    File file = new File(srcFilePath + downLoadFileName);//客户端要下载的文件
    FileInputStream fileInputStream = null;
    if (file.exists()) {//如果客户端指定的文件存在
    fileInputStream = new FileInputStream(srcFilePath + downLoadFileName);
    } else {//如果文件不存在,设置默认文件--d:\Server\兰亭序.mp3
    fileInputStream = new FileInputStream("d:\\Server\\兰亭序.mp3");
    }
    //5.输出数据
    byte[] fileData = new byte[1024];
    int length = 0;
    //通过socket获取数据通道
    OutputStream outputStream = socket.getOutputStream();
    while ((length = fileInputStream.read(fileData)) != -1) {//一边获取文件数据
    //一边将数据发送给客户端
    outputStream.write(fileData, 0, length);
    }
    socket.shutdownOutput();//设置结束写入标志
    //6.关闭相关资源
    outputStream.close();
    inputStream.close();
    fileInputStream.close();
    socket.close();
    serverSocket.close();
    System.out.println("服务端传输完毕...");
    }
    }

    客户端Homework03Client:

    package li.network.homework;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.InetAddress;
    import java.net.Socket;
    import java.util.Scanner;
    //客户端
    public class Homework03Client {
    public static void main(String[] args) throws IOException {
    //1.获得socket对象,指定连接的主机的IP和端口
    Socket socket = new Socket(InetAddress.getByName("192.168.1.6"), 9999);
    //2.获取数据通道,输出下载文件的名称
    OutputStream outputStream = socket.getOutputStream();
    //2.1通过键盘接收文件名称
    Scanner scanner = new Scanner(System.in);
    System.out.println("请输入下载的文件名称:(包括后缀)");
    String nameFile = scanner.next();
    //2.2输出数据
    outputStream.write(nameFile.getBytes());
    socket.shutdownOutput();//设置结束写入标志
    //3.读取返回的数据
    InputStream inputStream = socket.getInputStream();
    byte[] bytes = new byte[1024];
    int length = 0;
    FileOutputStream fileOutputStream =
    new FileOutputStream("d:\\Client\\" + nameFile);//保存的路径
    while ((length = inputStream.read(bytes)) != -1) {//循环读取数据通道的数据
    fileOutputStream.write(bytes, 0, length);
    }
    //4.关闭相关资源
    inputStream.close();
    outputStream.close();
    fileOutputStream.close();
    scanner.close();
    socket.close();
    System.out.println("客户端下载完毕...正确退出");
    }
    }

    服务端的文件夹如图:

    image-20220920011710436

    客户端的初始文件夹为空:

    image-20220920011927652

    运行服务端:

    image-20220920012011022

    运行客户端:

    image-20220920012112737 image-20220920012133238

    此时的客户端文件夹:

    image-20220920012252652
  • 相关阅读:
    文心一言 VS 讯飞星火 VS chatgpt (108)-- 算法导论10.1 6题
    unity简单数字拼图小游戏(源码)
    【LeetCode】42. 接雨水 - Go 语言题解
    Hexagon_V65_Programmers_Reference_Manual (50)
    windows下redis的安装及其他注意事项
    python Matplotlib绘制三维图
    Docker Desktop 和 WSL2 位置迁移
    9、Java——二维数组案例代码详解
    ssm基于J2EE的办公用品管理系统
    攻防世界-unseping
  • 原文地址:https://www.cnblogs.com/liyuelian/p/16709580.html