day26

本文介绍了设计模式中的单例模式和简单工厂模式,包括它们的实现方式和优缺点。此外,还概述了网络编程的基础,如IP地址、端口号和协议的重要性,以及Java中的InetAddress类用于IP地址的处理。最后,展示了UDP和TCP协议的简单应用,通过示例代码演示了数据的发送与接收过程。
摘要由CSDN通过智能技术生成

List item

一、设计模式

1、单例

1)StudentDemo

package com.shujia.lhw.day26.shejimoshi.danli;
/*
    创建型的第一种:
      单例模式:保证内存中只有一个对象

    如何保证一个类在内存中只允许一个对象存在呢?
      1、将构造方法私有化
      2、在类的成员变量的位置上创建一个对象
      3、提供一个公共的静态方法让外界获取到这个对象

    通过我们实现后发现,随着类的加载,对象就创建好了,这样的单例模式叫做饿汉式。

 */
public class StudentDemo {
    public static void main(String[] args) {
        Student s1 = Student.getStudent();
        Student s2 = Student.getStudent();
        System.out.println(s1 == s2);
        System.out.println(s1);
        System.out.println(s2);

    }

}
package com.shujia.lhw.day26.shejimoshi.danli;

public class Student {
    private static Student student= new Student();

    private Student(){}

    public static Student getStudent(){
        return student;
    }
}

2)TeacherDemo

package com.shujia.lhw.day26.shejimoshi.danli;
/*
    如何保证一个类在内存中只允许一个对象存在呢?
      1、将构造方法私有化
      2、在类的成员变量的位置上创建一个对象
      3、提供一个公共的静态方法让外界获取到这个对象

    饿汉式:类一加载,就创建对象
    懒汉式:用的时候,再去创建对象,但是内存中始终只有一个对象
      1、懒加载(延迟加载)
      2、容易产生线程安全问题
        1)在存在多线程环境中,只允许出现一个对象的类是共享数据
        2)并且有多条语句操作着共享数据
        3)需要使用锁来解决线程安全问题

     开发使用饿汉模式
     面试详细说懒汉式,懒汉式牵扯到线程安全问题

 */
public class TeacherDemo {
    public static void main(String[] args) {
        Teacher t1 = Teacher.getTeacher();
        Teacher t2 = Teacher.getTeacher();

        System.out.println(t1 == t2);
        System.out.println(t1);
        System.out.println(t2);
    }
}
package com.shujia.lhw.day26.shejimoshi.danli;

public class Teacher {
    private Teacher(){

    }

    private static Teacher t = null;

    //假设现在有3个线程,t1,t2,t3
//    public static Teacher getTeacher(){
//        synchronized(Teacher.class){
//            if(t == null){
//                //t1,t2,t3
//                t = new Teacher();
//            }
//            return t;
//        }
//    }

    //静态的同步方法
    public synchronized static Teacher getTeacher(){
        if (t == null){
            //t1,t2,t3
            t = new Teacher();
        }
        return t;
    }
}

2、简单工厂模式

1)AnimalDemo

package com.shujia.lhw.day26.shejimoshi.easyfactory;

/*
    简单工厂模式(静态工厂方法模式)

    优点:
      客户端不需要负责创建对象,从而明确了各个类的职责

    缺点:
      我们定义的静态工厂类负责对象的创建,如果有新的对象增加
      获取某些对象的创建方式不同,就需要不断地去修改工厂类,不利于后期维护

 */
public class AnimalDemo {
    public static void main(String[] args) {
//        Dog dog = new Dog();
//        dog.eat();
//        Cat cat = new Cat();
//        cat.eat();

        //通过动物工厂来获取对应的动物
//        Dog dog = AnimalFactory.createDog();
//        Cat cat = AnimalFactory.createCat();
//        dog.eat;
//        cat.eat;

        //将来我们还想获取熊猫,老虎等动物的时候,就要去修改AnimalFactory工厂类,但是呢,一般情况下,工厂类不允许被修改

        Animal dog = AnimalFactory.createAnimal("Dog");
        Animal cat = AnimalFactory.createAnimal("Cat");

        if (dog!=null){
            dog.eat();
        }

        if (cat!=null){
            cat.eat();
        }

        Animal pig = AnimalFactory.createAnimal("Pig");
        if (pig!=null){
            pig.eat();
        }


    }
}
package com.shujia.lhw.day26.shejimoshi.easyfactory;

public class AnimalFactory {
    //构造方法私有化,让外界无法创建该类的实例
    private AnimalFactory(){}

//    public static Dog createDog(){
//        return new Dog();
//    }
//
//    public static Cat createCat(){
//        return new Cat();
//    }

    //使用多态的形式修改
    public static Animal createAnimal(String type){
        if ("Cat".equals(type)){
            return new Cat();
        }else if("Dog".equals(type)){
            return new Dog();
        }else{
            System.out.println("该工厂不支持创建"+type+"类型的动物");
            return null;
        }
    }
}
package com.shujia.lhw.day26.shejimoshi.easyfactory;

public abstract class Animal {
    //吃
    public abstract void eat();
}
package com.shujia.lhw.day26.shejimoshi.easyfactory;

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("🐱吃🐟");
    }
}
package com.shujia.lhw.day26.shejimoshi.easyfactory;

public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("🐕吃🥩");
    }
}

3、工厂模式的优点

package com.shujia.lhw.day26.shejimoshi.factoryFunction;
/*
    工厂方法模式的优缺点:
      优点:
        客户端不需要负责对象的创建,从而明确各个类的职责
        如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可
        不影响其他的代码,后期容易维护,增强了系统的扩展性

      缺点:
        需要额外的写代码,增加了工作量
 */
public class AnimalDemo {
    public static void main(String[] args) {
        //我只想要狗
        DogFactory dogFactory = new DogFactory();
        Animal dog = dogFactory.createAnimal();
        dog.eat();

        //我想要只猫
        CatFactory catFactory = new CatFactory();
        Animal cat = catFactory.createAnimal();
        cat.eat();

        //我想要只猪
        PigFactory pigFactory = new PigFactory();
        Animal pig = pigFactory.createAnimal();
        pig.eat();
    }
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;

public abstract class Animal {
    public abstract void eat();
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("🐱吃🐟");
    }
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;

public class CatFactory implements Factory{
    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;

public class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("🐕吃🥩");
    }
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;

public class DogFactory implements Factory{
    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;

public interface Factory {
    public abstract Animal createAnimal();
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;

public class Pig extends Animal{
    @Override
    public void eat() {
        System.out.println("🐖吃饲料");
    }
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;

public class PigFactory implements Factory{
    @Override
    public Animal createAnimal() {
        return new Pig();
    }
}

4、设计模式总结

设计模式
  经验的总结

  1、创建型 创建对象
  2、结构型 对象的组成
  3、行为型 对象的功能

创建型模式:
  1、单例模式
    指的是在程序运行的过程中,内存只允许一个对象存在
    饿汉式
    懒汉式
  2、简单工厂模式
  3、工厂方法模式

二、网络编程

1、网络编程的三要素

网络编程的三要素:
  1、IP地址
  2、端口号
  3、协议

举例:
  假设某同学看上了一个女生,想要去表白。
  1、要去找这个女生     ---IP地址
  2、对Ta表白,跟Ta说话,对着耳朵说话     ---端口号
  3、要说什么呢?"I Love You"
    但是呢,这个女生没有学过英语,听不懂
    他就没有必要说英文,说她能听懂的语言,说汉语就可以,说“我爱你”   ---协议

IP地址:
  网络中计算机唯一标识

  但是呢,我们计算机只能识别二进制的数据,所以我们想IP地址在计算机中存储的时候应该也是由二进制的形式进行存储的

  IP:192.168.7.42
  换算成二进制:11000000.10101000.00000111.00101010
  实际上存储的是:11000000101010000000011100101010,这样的存储形式,我们在学习过程中,难免会遇到配置网络地址的操作,这样的IP地址
  从记忆和书写层面上来说都是很麻烦的

  为了方便IP地址的表示,就把IP地址上的每一个字节上的数据转换成十进制,然后字节与字节之间用.分割标识
  这样的表示法:点分十进制表示法

  11111111

  IP地址的组成:网络号段+主机号段
  IP地址的分类:
    A:定义一个号段定义为网络号段+后面三个号段都是为主机号段
      可以有多台主机相连:256*256*255
    B:前两个号段为网络号段+最后一个号段为主机号段 256*255
    C:前三个号段都是为网络号段+最后一个号段为主机号段 255 局域网
    D:224.0.0.1---239.255.255.254
    E:240.0.0.1---247.255.255.254

  特殊的IP地址:
     1、localhost = 本机 = 127.0.0.1
       127.0.0.1回环地址,可以用于测试本机的网络是否有问题,ping127.0.0.1

     2、广播地址:
       x.x.x.255

     3、网络地址:
       x.x.x.0

  三个DOS命令:
    ipconfig Windows:查看ip地址
    Linux:
      centOS6:ipconfig
      centOS7:ip addr

    ping:测试网络是否联通
      ping + IP地址/host名

2、InetAddress

package com.shujia.lhw.day26.network;

import java.net.InetAddress;

/*
    为了方便我们对IP地址的获取和操作,Java提供了一个类InetAddress供我们使用

    public static InetAddress getByName(String host)
        throws UnknownHostException确定主机名称的IP地址

 */
public class InetAddressDemo {
    public static void main(String[] args) throws Exception{
        InetAddress name = InetAddress.getByName("192.168.7.15");
        System.out.println(name);

        //public String getHostName()获取此IP地址的主机名
        String hostName = name.getHostName();
        System.out.println(hostName);

        //public String getHostAddress()返回文本显示的IP地址字符串
        String address = name.getHostAddress();
        System.out.println(address);
    }

}

3、ReceiveAndSend 1

package com.shujia.lhw.day26.network;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/*
    UDP协议接收数据:
      1、创建接收端的Socket对象
      2、创建一个数据包(接收容器)
      3、调用Socket对象的接收方法接收数据
      4、解析数据包,得到数据并显示到控制台上
      5、释放资源,关闭Socket

    注意事项:
      接收端程序在绑定同一个端口的时候不能同时运行多个

 */
public class ReceiveDemo1 {
    public static void main(String[] args) throws Exception{
        //1、创建接收端的Socket对象
        //DatagramSocket(int port)
        //构造数据报套接字并将其绑定到本地主机上的指定端口
        DatagramSocket ds = new DatagramSocket(10086);

        //2、创建一个数据包(接收容器)
        //定义一个字节数组
        byte[] bytes = new byte[1024];
        int length = bytes.length;
        //DatagramPacket(byte[] buf,int length)
        //构造一个DatagramPacket用于接收长度的数据包 length
        DatagramPacket datagramPacket = new DatagramPacket(bytes,length);

        //3、调用Socket对象接收方法接收数据
        ds.receive(datagramPacket);//程序阻塞,直到接收到数据

        InetAddress address = datagramPacket.getAddress();
        String ip = address.getHostAddress();

        //4、解析数据包,得到数据并显示在控制台上
        //public byte[] getData()返回数据缓冲区
        byte[] data = datagramPacket.getData();
        //public int getLength()返回要发送的数据的长度或接收到的数据的长度
        int length1 = datagramPacket.getLength();
        String s = new String(data,0,length1);
        System.out.println(ip+"发送的数据为:"+s);

        //释放资源,关闭Socket
        ds.close();
    }
}
package com.shujia.lhw.day26.network;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/*
    UDP协议发送数据:
      1、创建发送端的Socket对象
      2、创建数据,并把数据打包
      3、调用Socket对象的发送方法将数据发送数据
      4、释放资源,关闭Socket

 */
public class SendDemo1 {
    public static void main(String[] args) throws Exception{
        //1、创建发送端的Socket对象DatagramSocket
        //DatagramSocket()
        //构造数据报套接字并将其绑定到本地主机上的任何可用端口
        DatagramSocket ds = new DatagramSocket();
        //2、创建数据,并把数据打包
        byte[] bytes = "你好,大数据".getBytes();
        //获取数组的长度
        int length = bytes.length;
        //要发送的IP地址
        InetAddress address = InetAddress.getByName("192.168.7.15");
        //设置端口号
        int port = 10086;
        //3、调用Socket对象的发送方法将数据发送出去
        //DatagramPacket(byte[] buf,int length,InetAddress address,int port)
        //构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号
        DatagramPacket packet = new DatagramPacket(bytes,length,address,port);
        //从此套接字发送数据报包
        //void send(DatagramPacket p)
        ds.send(packet);

        //4、释放资源,关闭Socket
        ds.close();
    }
}

4、ReceiveAndSend 2

package com.shujia.lhw.day26.network;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class ReceiveDemo2 {
    public static void main(String[] args) throws Exception{
        //1、创建接收端的Socket对象
        DatagramSocket ds = new DatagramSocket(12345);

        while (true){
            //2、创建一个结束数据包
            byte[] bytes = new byte[1024];
            DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);

            //3、调用Socket对象的接受数据的方法接收数据
            ds.receive(datagramPacket);

            //4、解析数据
            String ip = datagramPacket.getAddress().getHostAddress();
            String hostName = datagramPacket.getAddress().getHostAddress();
            byte[] data = datagramPacket.getData();
            int length = datagramPacket.getLength();
            String s = new String(data,0,length);

            System.out.println(ip+":"+hostName+"发送的数据为:"+s);

        }

    }
}
package com.shujia.lhw.day26.network;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/*
    从键盘录入数据进行发送,如果输入的是886那么客户端就结束输入数据

 */
public class SendDemo2 {
    public static void main(String[] args) throws Exception{
        //1、创建发送端的Socket对象
        DatagramSocket ds = new DatagramSocket();

        //2、键盘录入数据
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        String line = null;
        while((line=br.readLine())!=null){
            if ("886".equals(line)){
                break;
            }

            //如果输入的数据不是886,将数据打包发送出去
            DatagramPacket packet = new DatagramPacket(line.getBytes(),line.getBytes().length, InetAddress.getByName
                    ("192.168.7.15"),12345);

            //调用Socket对象中发送数据包的方法
            ds.send(packet);
        }

        //释放资源
        ds.close();
    }
}

5、ServerAndClient 1

package com.shujia.lhw.day26.network;

import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/*
    TCP协议编写服务器代码:
      1、创建服务器端Socket对象(ServerSocket)
      2、调用accept()方法,监听客户端的连接,返回一个对应客户端连接的Socket对象
      3、获取通道中的输入流对象,读取客户端发送的数据,并显示在控制台上
      4、释放资源,关闭Socket服务

 */
public class ServerDemo1 {
    public static void main(String[] args) throws Exception{
        //1、创建服务器端Socket对象(ServerSocket)
        //ServerSocket(int port)
        //创建绑定到指定端口肚饿服务器套接字
        ServerSocket ss = new ServerSocket(12345);

        //调用accept()方法,监听客户端的连接,返回一个对应客户端连接的Socket对象
        Socket s = ss.accept();

        while(true){
            //获取通道中的输入流对象
            InputStream inputStream = s.getInputStream();
            byte[] bytes = new byte[1024];
            int length = inputStream.read(bytes);
            String s1 = new String(bytes,0,length);

            //获取客户端的IP
            String ip = s.getInetAddress().getHostAddress();
            String hostName = s.getInetAddress().getHostName();
            System.out.println(ip+":"+hostName+"发送的数据为:"+s1);
        }
    }
}
package com.shujia.lhw.day26.network;

import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;

/*
    TCP协议客户端代码实现:
      1、创建客户端的Socket对象
        这一步如果成功创建对象,就说明连接已经建立成功
      2、获取输出流对象,向服务器写数据
      3、释放资源,关闭Socket服务

    键盘录入数据

    注意事项:
      要先启动服务器端,再启动客户端,否则报连接被拒绝异常
 */
public class ClientDemo1 {
    public static void main(String[] args) throws Exception{

        //创建键盘录入对象
        Scanner sc = new Scanner(System.in);

        //创建发送端的Socket对象
        //Socket(InetAddress,address,int port)
        //创建流套接字并将其连接到指定的IP地址的指定端口号
//        Socket s = new Socket(InetAddress.getByName("192.168.7.15"),12345);

        //Socket(String host,int port)
        //创建流套接字并将其连接到指定主机上的指定端口号
        Socket s = new Socket("192.168.7.15",12345);

        //获取输出流对象,向服务器写数据
        OutputStream os = s.getOutputStream();
        while(true){
            String next = sc.next();

            if("886".equals(next)){
               break;
            }

            os.write(next.getBytes());
        }

        //释放资源,关闭Socket服务
        s.close();
    }
}

6、ServerAndClient 2

package com.shujia.lhw.day26.network;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerDemo2 {
    public static void main(String[] args) throws Exception{
        //1、创建服务器端的Socket对象
        ServerSocket ss = new ServerSocket(12345);

        //2、监听客户端的连接
        Socket s = ss.accept();

        //3、获取通道中字节输入流对象,接收客户端发送的信息
        InputStream is = s.getInputStream();
        //4、获取通道中的字节输出流对象,给客户端一个反馈
        OutputStream os = s.getOutputStream();

        while(true){
            byte[] bytes = new byte[1024];
            int length = is.read(bytes);
            String string = new String(bytes,0,length);
            String ip = s.getInetAddress().getHostAddress();
            String hostName = s.getInetAddress().getHostName();
            System.out.println(ip+":"+hostName+"发送的数据为:"+string);

            os.write("服务器已经接收到数据".getBytes());
        }
    }
}
package com.shujia.lhw.day26.network;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class ClientDemo2 {
    public static void main(String[] args) throws Exception{
        //1、创建客户端Socket对象
        Socket s = new Socket("192.168.7.15", 12345);

        //2、获取通道中字节输出流对象,往服务器发送信息
        OutputStream os = s.getOutputStream();
        //3、获取通道中字节输入流对象,接收服务器给的反馈
        InputStream is = s.getInputStream();
        while(true){
            Scanner sc = new Scanner(System.in);
            String next = sc.next();
            os.write(next.getBytes());

            byte[] bytes = new byte[1024];
            int length = is.read(bytes);
            String string = new String(bytes, 0, length);
            System.out.println("服务器给出反馈:"+string);
        }
    }
}

7、ServerAndClient 3

package com.shujia.lhw.day26.network;

import cn.tx.demo.WhileDemo;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;

/*
    用多线程改进服务器端代码,实现可以让多个客户端与之建立联系

 */
public class ServerDemo3 {
    public static void main(String[] args) throws Exception{
        System.out.println("================服务器启动=====================");
        //创建服务器端自身的Socket对象
        ServerSocket ss = new ServerSocket(12345);

        //监听的时候对应一个客户端,返回一个对相应的Socket对象
        //定义一个循环不断地接收客户端的连接请求
        while(true){
            //开始接受客户端与服务器端之间的连接
            Socket socket = ss.accept();
            new ServerReaderThread(socket).start();
        }

    }
}

//定义与客户端连接操作的线程类
class ServerReaderThread extends Thread{
    private Socket socket;

    ServerReaderThread(Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        //获取与客户端通道中的字节输入流对象

        try {
            InputStream is = socket.getInputStream();
            //将字节输入流对象包装成字符流
            InputStreamReader isr = new InputStreamReader(is);
            //使用字符缓冲输入流
            BufferedReader br = new BufferedReader(isr);
            //IP
            String ip = socket.getInetAddress().getHostName();
            String hostName = socket.getInetAddress().getHostName();
            //按照行来读取
            String line;
            while((line=br.readLine())!=null){
                //获取到当前时间
                Date date = new Date();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                String date2 = sdf.format(date);
                System.out.println(date2);
                System.out.println(ip+":"+hostName+"发送来的数据:"+line);
            }
        } catch (IOException e) {
//            e.printStackTrace();
        }
        System.out.println("客户端"+socket.getInetAddress().getHostName()+"下线了...");
    }
}
package com.shujia.lhw.day26.network;

import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

/*

 */
public class ClientDemo3 {
    public static void main(String[] args) throws Exception{
        //创建键盘录入对象
        Scanner sc = new Scanner(System.in);

        //创建客户端Socket对象
        Socket s = new Socket("192.168.7.15",12345);
        System.out.println("请输入想要发送的数据:");

        //获取通道中字节输出流对象
        OutputStream os = s.getOutputStream();
        OutputStreamWriter osw = new OutputStreamWriter(os);
        BufferedWriter bw = new BufferedWriter(osw);

        while (true){
            String next = sc.next();
            if("886".equals(next)){
                s.shutdownOutput();
                break;
            }

            bw.write(next);
            bw.newLine();
            bw.flush();
        }

        s.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘浩浩yyds

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值