Java - 网络编程、常见设计模式

发布于:2023-01-01 ⋅ 阅读:(147) ⋅ 点赞:(0)

Java - 网络编程、常见设计模式

一、网络编程

  1. 概述 - 不同电脑之间传输数据的途径

    • C/S 结构 - C现在主要是代表APP软件

    • C/S 优点 - 有一些逻辑可以放在客户端

    • Java开发其实两种结构都可以涉及,因为它们都有服务端,Java主要就是用于写服务端代码,主要接触的是B/S结构

  2. 网络通信协议

  3. 网络三要素

    • cmd: ping IP地址 用于测试能否连通另一台设备。

    • IPv4只够分40亿,明显是不够的,所以其实IP是动态分配的,你不用那就先不分,比如IP的4个数字,我最后一个数字让它在一定范围内变动,有人要用网络了我再挑一个分配给他。

    • 每个进程或者程序都需要有一个自己的端口,因为IP只能定位到设备,但是设备上可能安装了很多不同的软件,所以为了更好地数据传输,需要让程序有不同的接口,不然会冲突。

  4. IP地址API

    //获取本机ip地址对象
    InetAddress ip1= InetAddress.getLocalHost();
    System.out.println(ip1);
    System.out.println(ip1.getHostName());
    System.out.println(ip1.getHostAddress());
    System.out.println("--------");
    
    //通过主机名获取ip地址对象
    //InetAddress ip2= InetAddress.getByName("192.168.17.46");
    InetAddress ip2= InetAddress.getByName("DESKTOP-UETTPA7");
    System.out.println(ip2);
    System.out.println(ip2.getHostName());
    System.out.println(ip2.getHostAddress());
    
  5. UDP协议

    • 概述

    • UDP通信过程

  6. UDP协议编程

    • UDP就像收音机与广播,你没调到那个频道,它也在不停的推送,当你调到了那个频道,就能接收到了;就像直播软件,他是一直在发送数据的,你的网络卡了,但是等一会好了之后它又会自己连上,但是如果用的是TCP协议,一旦断了,那就必须要重新连接,因为它必须保证互相连通才会发送数据。
    • UDP - 先运行客户端,再运行服务端才看得到效果

    • 发送端代码

      public static void main(String[] args) throws Exception {
          //发送端
          //数据包对象:DatagramPacket(byte[] buf, int length, InetAddress address, int port):创建发送端数据包对象
          //套接字对象:DatagramSocket() 创建发送端的Socket对象,系统会随机分配一个端口号。
          //套接字方法: void send(DatagramPacket dp) 发送数据包
      
          //准备好包对象
          byte[] buf ="你好啊,我是发送端,送你一端美妙的音乐~".getBytes();
          //buf.length不是固定的,以实际要传输的数据内容为准
          //如果想发送给一个网段192.168.10.XXX    255广播地址
          DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), 8888);
      
      
          //发送数据
          DatagramSocket send = new DatagramSocket();
          send.send(packet);
      
      
          //关闭资源
          //send.close();
      
      }
      
    • 接收端代码

      public static void main(String[] args) throws Exception {
          //接收端
          //数据包对象:DatagramPacket(byte[] buf, int length):创建接收端数据包对象
          //int getLength() 获得实际接收到的字节个数
          //InetAddress getAddress() 获取ip地址对象
          //套接字对象: DatagramSocket(int port) 创建接收端的Socket对象并指定端口号
          //套接字方法 : void receive(DatagramPacket p) 接收数据包
      
      
          //准备好包对象
          byte[] buf = new byte[1024];
          DatagramPacket packet = new DatagramPacket(buf, buf.length);
      
          //接收数据
          DatagramSocket receive = new DatagramSocket(8888);
          receive.receive(packet);
      
          //处理数据
          int length = packet.getLength();
          System.out.println(new String(buf, 0, length));
          System.out.println("发送者是:" + packet.getAddress());
      
          //关闭资源
          receive.close();
      }
      
  7. TCP协议

    • 概述

    • TCP通信过程

  8. TCP协议编程

  9. TCP协议练习1 - 文本上传

    • 思路

    • 图解

    • 服务器处理线程 代码 - 因为一个服务端要处理多个客户端的需求

      public class UploadThread extends Thread {
          private Socket server;
      
          public UploadThread(Socket server) {
              this.server = server;
          }
      
          @Override
          public void run() {
              try {
      
                  InputStream is = server.getInputStream();
                  BufferedInputStream bis = new BufferedInputStream(is);
                  FileOutputStream fos = new FileOutputStream("day12\\imageCopy" + System.currentTimeMillis() + ".jpg");
                  BufferedOutputStream bos = new BufferedOutputStream(fos);
                  //重复读(从管道读)写(写到本地)
                  int len = -1;
                  byte[] bys = new byte[1024];
                  //①从管道读取数据
                  while ((len = bis.read(bys)) != -1) {//read方法是阻塞式(没数据不读)
                      //②将读取到的数据写出到本地
                      bos.write(bys, 0, len);
                  }
      
                  //给出反馈
                  OutputStream os = server.getOutputStream();
                  os.write("数据上传成功".getBytes());
      
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  if (server != null) {
                      //关闭连接对象
                      try {
                          server.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
              }
          }
      }
      
    • 服务端代码

      public static void main(String[] args) throws Exception {
          //创建服务器对象
          ServerSocket serverSocket = new ServerSocket(8888);
      
          while (true) {
              //获取连接对象  一定要放到循环的里面,避免死循环重复执行。
              Socket server = serverSocket.accept();//阻塞式
      
              UploadThread ut = new UploadThread(server);
              ut.start();
          }
      }
      
    • 客户端代码

      public static void main(String[] args) throws IOException {
          //创建客户端对象
          Socket client = new Socket("localhost", 8888);
      
      
          FileInputStream fis = new FileInputStream("day12\\image.jpg");
          BufferedInputStream bis = new BufferedInputStream(fis);
          OutputStream os = client.getOutputStream();
          BufferedOutputStream bos = new BufferedOutputStream(os);
      
          //重复读(从本地读)写(写到管道)
          int len = -1;
          byte[] bys = new byte[1024];
          //①从“本地”读取文件到内存中
          while ((len = bis.read(bys)) != -1) {//read方法是阻塞式(没数据不读)
              //②将内存中的数据写入管道中
              bos.write(bys, 0, len);
          }
          //客户端发送玩数据后,高速服务器端(关闭客户端对象输出流)
          client.shutdownOutput();
      
          //接受服务器反馈(从管道)
          InputStream is = client.getInputStream();
          int len2 = is.read(bys);//等数据
          System.out.println(new String(bys, 0, len2));
      
          //关客户端
          client.close();
      }
      
  10. TCP协议练习2 - BS结构服务器

    • 思路

    • 请求与响应

    • 注意事项

      · 浏览器访问路径:http://localhost:8899/web/index.html

      · https 协议会对传输的东西加密,拿到的信息会乱码,不好处理; 所以自己开发用 http 就行

      · 浏览器发送过来的请求信息如下:请求头和请求体中间是有一个空格的

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Dqjc3IHH-1662048071612)(C:\Users\ASUS\Desktop\学习笔记\自己\笔记截图\image-20220831153415420.png)]

    • 服务器处理线程 代码 - 浏览器会多次请求服务器连接,因为加载图片的时候会需要再连一下服务器

      public class BSThread extends Thread {
          private Socket server;
      
          public BSThread(Socket server) {
              this.server = server;
          }
      
          @Override
          public void run() {
              try {
                  //接受浏览器发送过来的数据
                  InputStream is = server.getInputStream();
                  //转换流:将is转为字符流
                  InputStreamReader isr = new InputStreamReader(is);
                  //使用字符输入缓冲流读取数据
                  BufferedReader br = new BufferedReader(isr);
                  //读取一行数据(请求头)
                  String line = br.readLine();
                  //System.out.println(line);//"GET /web/index.html HTTP/1.1"
      
                  //分析数据,找到浏览器要的文件(index.html)的路径
                  String[] strs = line.split(" ");//{"GET"    "/web/index.html"  "HTTP/1.1""}
                  //strs[1]//   "/web/index.html"  截取 "web/index.html"
                  String path = strs[1].substring(1);
                  System.out.println(path);//web/index.html
                  String endPath = "day12\\" + path;  //  day12\\web\\index.html
      
                  //读取路径的数据,将数据写出到通道
                  FileInputStream fis = new FileInputStream(endPath);
                  OutputStream os = server.getOutputStream();
                  //发送给浏览器  相应数据
                  os.write("HTTP/1.1 200 OK\r\n".getBytes() );//响应头
                  os.write("Content-Type:text/html\r\n".getBytes() );
                  os.write("\r\n".getBytes() );
                  int len = -1;
                  byte[] bys = new byte[1024];
                  while ((len = fis.read(bys)) != -1) {
                      os.write(bys,0,len);
                  }
              } catch (IOException e) {
                  e.printStackTrace();
              } finally {
                  //关闭连接对象
                  if (server!=null){
                      try {
                          server.close();
                      } catch (IOException e) {
                          e.printStackTrace();
                      }
                  }
      
              }
          }
      }
      
    • 服务端代码

      //由于浏览器访问数据,只需要写一个服务器,通过浏览器的访问,将数据提交给浏览器。
      //提交index.html内容给浏览器
      public class BSServer {
          public static void main(String[] args) throws Exception {
              //创建服务器对象
              ServerSocket serverSocket = new ServerSocket(8888);
      
              while (true) {
                  //获取连接对象
                  Socket server = serverSocket.accept();
                  //获取连接对象
                  System.out.println("浏览器已连接服务器...");
                  new BSThread(server).start();
              }
          }
      }
      

二、设计模式

  1. 单例模式

    • 概述

    • 饿汉式模式

    • 懒汉式模式 - 第一次调用方法的时候,会把对象实例化,以后再调用方法得到的也是第一次的对象

  2. 多例模式

    • 概述

    • 通用对象模式 - 在类中定义一个成员变量 集合 放一定数量的对象,可以通过下标随机数取其中的某个对象

    • 特定对象模式 - 在类中定义不同的成员变量,赋值为一个新对象

  3. 工厂模式

    • 概述