Java基础5

目录

一.多线程的创建方式

1.1多线程的创建方式1 ----继承Thread类

1.2多线程的创建方式2:---要实现Runnable接口

1.3创建线程的方式3 :线程池

二.Java设计模式 结构型设计-->代理模式--静态代理

三.解决线程安全问题

四.同步锁synchronized----->同步方法:将synchronized声明到方法上

五.什么是同步机制

5.1同步机制:

5.2wait()和sleep()的区别?

六.等待唤醒机制

七.throw和throws的区别?

八.jdk5以后Lock锁---->ReetrantLock可重入的互斥锁

九.线程池

9.1什么是线程池

9.2线程池的优化 参数调优(7大参数)

十.Java提供的Timer定时器--执行定时任务TimerTask

十一.文件的基本操作

11.2文件的基本功能

11.3文件高级功能

11.4递归算法

十二.IO流

12.1流的分类

12.2基本功能

12.3字符流

12.4序列化和反序列化作用

十二.java.util.Properties(很重要):属性列表集合类

十三.网络编程

13.1UDP发送端和接收端的实现(了解) --->不可靠连接

13.2TCP客户端和服务器端的实现---->安全---可靠连接(使用居多)


一.多线程的创建方式

1.1多线程的创建方式1 ----继承Thread类

1)自定义一个类继承自Thread,"线程类"
2)重写Thread类的run方法
3)在main用户线程中,创建当前类对象,
4)start()启动线程----->jvm调用run方法,结果---多个线程并发执行!
class MyThread extends Thread{
    
    public void run(){
        //完成耗时的操作
    }
}
​
public class TestTread{
    public static void main(String[] args){
        //创建线程类对象
        MyThread my1=  new MyThread() ;
        MyThread my2=  new MyThread() ;
        ///设置线程名称
        my1.setName("t1") ;
        my2.setName("t2") ;
        //启动线程
        my1.start() ;
        my2.start();
    }
}

1.2多线程的创建方式2:---要实现Runnable接口

1)自定义一个类实现Runnable接口,
2)实现接口里面的run方法--->完成耗时操作
3)在main用户线程中创建当前这个类的实例--->"资源类对象"
4)创建线程类Thread对象,然后将3)资源类对象 作为参数传递.
5)启动线程!start();
   
    class MyRunnable implements Runnable{}//实现接口
    MyRunnable my = new MyRunnable() ; ---->真实角色
    Thread  t1  = new Thread(my,"t1") ; ---->Thread代理角色
    t1.start();

1.3创建线程的方式3 :线程池

1)自定义一个类实现Callable接口,实现里面call方法,完成异步任务的操作
    2)创建线程池 Executors.newFixedThreadPool(线程数) ;---->ExecutorService
                        submit(Callable call)
                        submit(Runnable run)
​
    public class ExecutorsDemo {
    public static void main(String[] args) {
        // 创建一个线程池对象,控制要创建几个线程对象。
        // public static ExecutorService newFixedThreadPool(int nThreads)
        ExecutorService pool = Executors.newFixedThreadPool(2);
        // 可以执行Runnable对象或者Callable对象代表的线程
        pool.submit(new MyRunnable());
        pool.submit(new MyRunnable()); 
        pool.shutdown();//结束线程池
    }
}

二.Java设计模式 结构型设计-->代理模式--静态代理

代理设计模式
代理核心思想:
     真实角色专注自己的事情(开发中,针对自己的业务)
     代理角色帮助真实完成一件事情
    静态代理:
        代理角色和真实角色要实现同一个接口
    动态代理:
        jdk动态代理-―-前提必须有接口
        cglib动态代理--->基于类就可以

三.解决线程安全问题

校验多线程安全问题的标准 (使用标准来看多线程环境是否存在问题,以及解决方案)
    1)是否是多线程环境   --->是
    2)是否有共享数据    ---> 是存在的
    3)是否有多条语句对共享数据操作
          tickets票:多条语句同时操作
    将3)多条语句多共享数据的操作使用同步代码块包起来---解决线程安全问题    
synchronized(锁对象){
    将多条语句多共享数据的包裹起来
}
锁对象:可以是任意Java类对象(多个线程必须使用同一个锁!否则锁不住)
可能出现死锁死锁:
    使用synchronized解决线程安全问题,安全问题解决了,效率低,可能死锁现象
    死锁:两个线程出现了一种互相等待的情况,A线程等待B线程释放锁,B线程等待A线程释放锁,造成死锁现象!
    解决死锁问题--->线程之间的通信必须使用的同一个资源!  (生产者和消费者模式思想)
​
消费者生产者模式思想------"信号灯法"

四.同步锁synchronized----->同步方法:将synchronized声明到方法上

什么是同步方法(非静态)?如果一个方法中第一句话是一个同步代码块,可以将synchronized关键字定义在声明上---->同步方法
          权限修饰符  synchronized 返回值类型 方法名(参数列表){
              ...
          }
          锁对象:this---代表类对象的地址值引用
          如果是静态的同步方法,锁对象---->当前类名.class(字节码文件对象)

五.什么是同步机制

5.1同步机制:

 多个线程在并发的使用公共的某个变量(被共用),,保证同步(保证安全),某个线程在当前这个数据进行持有的时候,其他线程是不能访问的----通过synchronized同步代码块就可以解决线程安全问题
        synchronized(监视器){
        
        }
    1)需要将多条语句对共享数据进行操作使用同步代码块包裹起来
    2)同步机制里面的监视器,俗称"锁",可以是任意Java类对象,多个线程必须使用同一个监视器
        或者使用同步方法(非静态)---锁对象this
        静态的同步方法--->锁对象当前类名.class字节码文件对象
​
​
同步机制:
    包括wait()和notify()
        这两个方法都是监视器(锁)有关系,锁对象可以是任意Java类型(jdk提供 任何类,自定义的类),Object代表所有类的父类,任意Java对象可以使用Object,所以这些都定义在Object类中.
    volatile关键字  保证当前实例是线程安全

5.2wait()和sleep()的区别?

1)来源不同
    wait()来自于Object,被锁对象调用的
    sleep()来自于Thread,线程睡眠,通过线程对象调用的
2)是否会释放锁
    wait()方法的调用,会立即释放锁,才能通过notify()唤醒对方线程,达到同步安全
    sleep()只是Thread类的普通方法,跟锁没有关系,睡眠中,线程处于阻塞状态,当线程睡眠时间到,线程继续执行
3)共同点都会抛出异常 throws InterruptedException:中断异常

六.等待唤醒机制

等待唤醒机制--->使用"信号灯法"解决线程安全前提下,造成死锁,多个线程使用同一个资源对象
使用生成者消费者模式思想:
    使用生成者不断的产生数据,消费者不断的使用数据(展示数据)
    当生成者等待先产生数据之后,需要通知消费者使用数据
    消费者线程等待 先去使用数据,当前没有数据了,需要通知生成者产生数据!
    
    在synchronized同步代码块/同步方法,需要使用监视器(锁)调用wait()和notify(),调用wait()会立即释放锁,完成唤醒的操作!

七.throw和throws的区别?

throws和throw共同点都是抛出的异常!
throws:
    1)抛出是在方法声明上抛出
    public static Date string2Date(String source,String pattern) throws ParseException,Exception{
        return new SimplateDateFormat(pattern).parse(source) ;
        
        //String dateStr ="2022-11-22" ;
        //使用SimplateDateFormat里面传递的模式 "yyyy年MM月dd日",跟上面的格式不一致
    }
    2)throws的后面跟的异常类名,可以跟多个异常类名,中间逗号隔开
    3)针对throws抛出的方法处理,谁调用这个方法,谁必须处理! (处理方式---交给调用者,继续throws或者try..catch...finally)
    4)throws它表示抛出异常的可能性
    
throw:
    1)抛出是在方法体语句中
    2)后面跟是异常对象名  throw new XXXEception(),只能某个异常对象名
    3)throw抛出的处理---交个方法中逻辑语句处理 if语句
    4)它表示抛出异常的肯定性,执行某段代码一定会有这个异常!

八.jdk5以后Lock锁---->ReetrantLock可重入的互斥锁

Lock接口
    LockLock实现提供比使用synchronized方法和语句可以获得的更广泛的锁定操作.
实现类:
    可重入的互斥锁   java.util.concurrent.locks.ReentrantLock
    获取锁:指定的某个时刻   public void lock()
    释放锁 : public void unlock()  
格式:
    Lock l = ...;
      l.lock();
        try {
            //访问受此锁保护的资源
        } finally {
                l.unlock();    //释放锁(系统相关的资源)
       }
步骤:
    1)//可重入的互斥锁
    private Lock lock = new ReentrantLock() ;
    2)//获取锁
    lock.lock();
    3)//释放锁
    lock.unlock();

九.线程池

9.1什么是线程池

什么是线程池:
    会创建一些固定的可重复使用的线程数,会在线程池中,循环利用.当某些线程使用完毕,不会被释放掉,而是归还线程池中,等待下一次再去利用!
线程池的特点:
    1)降低资源销毁,因为线程使用完毕的时候,归还到线程中继续使用!
    2)提高线程的维护,还是借助线程池的参数

9.2线程池的优化 参数调优(7大参数)

corePoolSize:核心线程数量
    maxmumPoolSize:最大核心线程数
    workQueue:阻塞队列
    keepAliveTime:生存时间
    TimeUnit unit:时间计量单位
    handler:拒绝策略:当线程数已经到最大线核心线程池并且同时workeQueue里面队列到达满的状态,线程池会启用拒绝策略!            ---->里面也是子实现类---->都是Exceutors的静态内部类
    
    ThreadFactory: 创建线程的工厂------>创建默认的线程池的名称以及后面的序列编号/同时创建线程
                    ----->子实现类DefaultThreadFactory--->Exceutors的静态内部类
                    pool-1-Thread-1
                    pool-1-Thread-2
                    ....

十.Java提供的Timer定时器--执行定时任务TimerTask

构造方法:

Timer():创建一个计时器

成员方法:

  public void cancel()    取消定时器
    void schedule(TimerTask task, Date time):   在给定的日期时间来执行TimerTask定时任务  --->
        String dataStr = "2022-11-22 18:00" ;//---->日期文本---->java.util.Date
        (应用场景:引入使用io流的方式,在指定时间点上,删除指定带内容的目录里面的所有.java文件)
​
    void schedule(TimerTask task, long delay)  :在给定多少毫秒后(延迟时间)执行这个定时任务
    public void schedule(TimerTask task,long delay,long period):在指定延迟时间(delay)执行任务,然后每经过固定延迟时间(period)重复执行任务
    
    schedule这些方法第一个参数都是定时任务:TimerTask是一个抽象类,
     1)可以定义具体的子类继承自TimerTask
     2)直接可以使用抽象类的匿名内部类

十一.文件的基本操作

11.2文件的基本功能

使用java.io.File来描述路径形式
    描述 "D:\EE_2211\day23\code\Employee.java"
    File(File parent, String child)
    File(String pathname) 推荐第二个
    File(String parent, String child)
    
创建文件/文件夹
    public boolean createNewFile()throws IOException:创建文件,如果不存在,创建,返回true
    public boolean mkdir():创建文件夹,如果存在了,则返回false;否则true
    public boolean mkdirs():创建多级目录,当父目录不存在的时候创建
判断
    public boolean isFile():是否是文件       使用居多
    public boolean isDirectory():是否是文件夹  使用居多
    public boolean isAbsolute():是否为绝对路径
    public boolean exists():判断文件或者目录是否存在
删除
    public boolean delete():删除由此抽象路径名表示的文件或目录 (删除目录,目录必须为空)

11.3文件高级功能

11.3.1获取指定目录下的所有的文件夹以及文件的Fiie数组

例题:获取E/D盘下的所有的以.jpg结尾的文件
java.io.File:高级功能
    //public File[] listFiles():获取指定抽象路径表示下的所有的File数组  推荐---->使用File的功能进行判断
    //public String[] list():抽象路径名表示的目录中的文件和目录。
    
    public class FileTest {
    public static void main(String[] args) {
​
        //1)描述磁盘上抽象路径的表示d://
        File file = new File("D://") ;
        //public String[] list():抽象路径名表示的目录中的文件和目录。
       /* String[] strs = file.list();
        for(String s:strs){
            System.out.println(s) ;
        }*/
        //public File[] listFiles():获取指定抽象路径表示下的所有的File数组  推荐---->使用File的功能进行判断
        File[] files = file.listFiles();
        //遍历之前:非空判断,防止空指针异常
        if(files!=null){
            for(File f :files){
                //f---->有文件/文件夹
                //判断是文件
                if(f.isFile()){
                    //以.jpg结尾
                    if(f.getName().endsWith(".jpg")){//.endsWith以...结尾
                        System.out.println(f.getName());//String getName():获取File指定的路径的文件或者文件的名称
                    }
                }
            }
        }
    }
}

11.4递归算法

方法调用方法本身的一种现象!(并非是方法嵌套方法)
递归的使用:
    1)需要定义一个方法
    2)有规律
    3)必须有出口条件----->"死递归"
    
需求:求5的阶乘
   使用求阶乘思想完成
   使用递归思想
        解决问题的思路:
               将问题1--->进行分解若干小问题
                      问题11
                      问题12
                           ...
public class DiGuiDemo {
​
   public static void main(String[] args) {
​
       //使用求阶乘思想完成
       //定义一个结果变量
       int jc = 1 ;
       for(int x = 2 ;x<=5 ; x ++){
           jc*=x ;
       }
       System.out.println("5的阶乘是:"+jc);
​
       System.out.println("-------------------------------------") ;
       System.out.println("5的阶乘是:"+jieCheng(5));
   }
​
    //定义求5的阶乘的方法
    private static int jieCheng(int n) {//5
       if(n==1){
           return  1 ;
       }else {
           //如果不是1
           //5*调用方法名(5-1)
           return n * jieCheng(n-1) ;
           //5 *4*3*2*jiecheng(1)
       }
    }
}

11.4.1不死神兔问题。

public class Test1 {
    public static void main(String[] args) {
        //数组的方式去实现
        //创建一个数组:动态初始化
        int[] arr = new int[20] ; //第二十个月
        //第一个月和第二个都是1
        arr[0] = 1 ;
        arr[1] = 1 ;
        //从第三个月开始,每一月兔子对数是前两个月兔子对数之和!
        for(int x = 2 ;x<arr.length;x++){
            arr[x] = arr[x-1] + arr[x-2] ;
        }
        //输出最后一个元素
        System.out.println("第二十个月兔子对数:"+arr[19]); //6765
        System.out.println("-----------------------------------------------------") ;
​
        //递归:定义一个方法
        long time = System.currentTimeMillis() ;
        System.out.println("第二十个月的兔子的对数是:"+getRabbit(20));
        long end = System.currentTimeMillis();
        System.out.println("耗时"+(end-time)+"毫秒");
    }
    //定义一个方法
    public static int getRabbit(int n){//代表的第几个月
        //第一个月和第二个月兔子的对数是1---->方法递归的出口条件
        if(n==1 || n==2){
            return  1;
        }else {
            //从第三个月开始,每一个月兔子对数是前两个月兔子对数之和!
            return getRabbit(n-1)+getRabbit(n-2) ;
        }
    }
}

十二.IO流

12.1流的分类

按流的方向划分两大类:
        输入流
        输出流
按类型划分:
        字节流
            字节输入流:InputStream
                        基本的字节输入流:FileInputStream
                        
                        字节缓冲输入流:BufferedInputStream 
            字节输出流:OutputStream
                        基本的字节输出流:FileOutputStream
                        字节缓冲输出流BufferedOutputStream
        字符流
            字符输入流:Reader
                            FileReader 
                        字符缓冲输入流:BufferedReader
            字符输出流:writer
                            FileWriter
                        字符缓冲输出流 :BufferedWriter 
当使用记事本打开能读懂的就使用字符;打开读不懂,用字节!(读图片文件/视频/音频)

12.2基本功能

12.2.1末尾追加

 //public FileOutputStream(String name,boolean append) throws FileNotFoundException
//创建字节文件输出流对象,实现文件的末尾追加,而不将之前覆盖,第二个参数必须为true
        FileOutputStream fos = new FileOutputStream("fos2.txt",true) ;
        //for循环
        for(int x = 0 ; x < 10;x++){
            fos.write(("hello"+x).getBytes());//getBytes()获取字节
            //写一次数据,换一次行
            fos.write("\r\n".getBytes());
        }
        //释放资源
        fos.close();

12.2.2输入流读文件

步骤:
    1)创建文件输入流对象
    2)读文件
        public int read() throws IOException:一次读取一个字节,返回字节数
        public int read(byte[] b) throws IOException:一次读取一个字节数组
    3)释放资源
实现过程:
方式一:使用基本字节流一次读取一个字节:
    //1)创建文件字节输入流对象
     FileInputStream fis = new FileInputStream("IODemo3.java") ;
    //2)读文件
    //有一个字节数:从0开始
     int len = 0 ;
     while((len=fis.read())!=-1){ //read()阻塞式方法  //len赋值给流对象调用的读的方法,判断一块在这里用
        System.out.print((char)len) ;//将数据展示控制台上
     }
​
    //3)释放资源
    fis.close();
方式二:使用基本字节流一次读取一个字节数组:
    //创建一个字节文件输入流对象
    FileInputStream fis = new FileInputStream("IODemo3.java" ) ;
    //一次读取一个字节数组,字节数组长度,1024或者1024的整数倍
    byte[] bytes = new byte[1024] ;
    //总字节数
    int len = 0 ;
    while((len=fis.read(bytes))!=-1){ //赋值,判断一块使用
        //将数据展示控制台上
        System.out.println(new String(bytes,0,len));
    }
    //释放资源
    fis.close() ;
​

12.2.3复制文件

方式一:使用基本字节流一次读取一个字节:
        //使用文件字节输入流操作源文件
        FileInputStream fis = new FileInputStream(srcFile) ;
        //使用文件字节输出流操作目的地文件
        FileOutputStream fos = new FileOutputStream(destFile) ;
​
        //一次读取一个字节
        int len = 0 ;
        while((len=fis.read())!=-1){
            //读一个字节,给fos流对象中写一个字节,写入到目标文件中
            fos.write(len) ;
        }
​
        //释放资源
        fos.close();
        fis.close();
方式二:使用基本字节流一次读取一个字节数组:
        //使用文件字节输入流操作源文件
        FileInputStream fis = new FileInputStream(srcFile) ;
        //使用文件字节输出流操作目的地文件
        FileOutputStream fos = new FileOutputStream(destFile) ;
​
        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        //实际字节数
        int len = 0 ;
        while ((len=fis.read(bytes))!=-1){
            //一次读取一个字节数组从字节输入流中,
            //一次写一个字节数组,通过fos写入到destFile中
            fos.write(bytes,0,len);
        }
​
        //释放
        fos.close();
        fis.close();

12.2.4Buffered

Bufferered键盘录入

 InputStream in = System.in ; //标准输入流---等待录入
        //创建字符输入流:Reader抽象类
        //InputStreamReader是具体的子类 构造方法InputStreamReader(InputStream in )
        Reader reader = new InputStreamReader(in) ;
        //创建一个字符缓冲输入流对象
        BufferedReader br = new BufferedReader(reader) ;
​
        //提示并录入
        System.out.println("请您输入一个字符串:");
        //利用BufferedReader一次读取一行
        String line = br.readLine() ;
        System.out.println("您录入的数据是:"+line) ;

字节缓冲流复制文件

字节缓冲流的方式
        使用字节缓冲流的方式一次读取一个字节  
        使用字节缓冲流的方式一次读取一个字节数组  
        
        public class CopyFileTest {
    public static void main(String[] args) throws IOException {
        //D:\EE_2211\day24\a.mp4---复制到 当前项目copy.mp4
        long start = System.currentTimeMillis() ;
       // copyFile("D:\\EE_2211\\day24\\a.mp4","copy.mp4") ;
        copyFile2("D:\\EE_2211\\day24\\a.mp4","copy.mp4") ;
        long end = System.currentTimeMillis() ;
        System.out.println("共耗时:"+(end-start)+"毫秒");
    }
​
    //字节缓冲流一次读取一个字节数组
    public static void copyFile2(String srcFile, String destFile) throws IOException {
        //创建字节缓冲输入流对象
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(srcFile)) ;
        //创建字节缓冲输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(destFile)) ;
​
        //一次读取一个字节数组
        byte[] bytes = new byte[1024] ;
        int len = 0 ;
        while((len=bis.read(bytes))!=-1){
            bos.write(bytes,0,len);
​
        }
        bos.flush() ;//强制刷新缓冲字节  (网络中 TCP传输协议,这种场景刷新,客户端文件---传给服务器端)
​
        //释放资源
        bos.close();
        bis.close();
    }
​
    //字节缓冲流一次读取一个字节
    public static void copyFile(String srcFile, String destFile) throws IOException {
        //创建字节缓冲输入流对象
        BufferedInputStream bis = new BufferedInputStream(
                new FileInputStream(srcFile)) ;
        //创建字节缓冲输出流对象
        BufferedOutputStream bos = new BufferedOutputStream(
                new FileOutputStream(destFile)) ;
​
        //一次读取一个字节
        int by = 0 ;
        while((by=bis.read())!=-1){
            //写一个字节
            bos.write(by) ;
        }
        //释放资源
        bos.close();
        bis.close();
    }
}
    
        

12.3字符流

12.3.1Writer

Writer:具体的子类
    public OutputStreamWriter(OutputStream out):
    字符转换输出流(可以将基本字节输出流转换成字符输出流),平台默认的字符集编码(idea,utf-8)
    public OutputStreamWriter(OutputStream out,String charsetName):
    字符转换输出流 ,指定一个编码字符集
写的功能:
    void write(char[] cbuf)写入一个字符数组。
    abstract void write(char[] cbuf, int off, int len) 写入字符数组的一部分。
    void write(int c)  写一个字符
    void write(String str)写一个字符串
    void write(String str, int off, int len) :写入字符串的一部分

12.3.2Reader

Reader:抽象类,具体子类
    public InputStreamReader(InputStream in):创建字符转换输入流,以平台默认字符集解码
    public InputStreamReader(InputStream in,String  charsetName):创建字符转换输入流对象,指定字符集解码
read的功能
    public int read(char[] cbuf):读取字符数组
    public int read():读一个字符
    InputStreamReader/OutputStreamWriter:字符转换流弊端:代码格式复杂,不能直接操作文件!

12.4序列化和反序列化作用

序列化:前提条件:当前这类型必须实现java.io.serializable接口
    将Java对象(成员信息等) 变成  "流数据",在服务器之间数据传输
反序列化:
        即将序列化流中的数据---->ObjectInputStream---->还原成对象!
        
大部分的常用类都已经实现了java.io.serializable接口,后期Java后端程序和前端的中间连接层---->底层框架
Servlet(Server Applet)---->里面给产生固定的serialVersionUID

十二.java.util.Properties(很重要):属性列表集合类

Properties类表示一组持久的属性。
Properties可以保存到流中或从流中加载。(重要的地方)
属性列表中的每个键及其对应的值都是一个字符串。
​
继承Hashtable---->实现Map接口---->存储数据,取出数据----都可以使用Map的方式
构造方法:

public Properties():创建空的属性列表
特有方法

java.util.Properites属性列表有自己的遍历方式---底层基于Map实现的
       添加元素:
               public Object setProperty(String key, String value)
       遍历属性列表
               public Set<String> stringPropertyNames()获取属性列表中的所有的键
               public String getProperty(String key)使用此属性列表中指定的键搜索属性

十三.网络编程

数据在网络中不断进行传输
网络编程三要素:

ip: 使用点分十进制法,中间使用.隔开
    A类  国家大部门---->前一个号段是网络号段,后面三个主机号段
    B类  校园/大公司服务器机房/:前面两个网络号段,后面使用两个注解号段
    C类  私人地址:前面三个为网络号段,后面是主机号段
port端口
    port端口 360软件都可以查看你电脑所有客户端软件的端口号
    范围:0~65535  里面0~1024属于保留端口
传输协议
    UDP协议--->数据报包(数据包的报文)
        1)不需要建立连接通道
        2)不可靠协议,不安全的
        3)发送数据大小有限制
    TCP协议--->最基本的字节流的方式发送数据
        1)就必须连接通道
        2)可靠协议,一种安全
        3)发送数据大小无限制

13.1UDP发送端和接收端的实现(了解) --->不可靠连接

UDP发送端的代码实现

 //1)创建发送端的socket
        DatagramSocket ds = new DatagramSocket() ;
        // 2)创建数据报包DatagramPacket       
         /** public DatagramPacket(byte[] buf,  要发送数据---转换成字节数组
         *                       int length,  实际字节数长度
         *                       InetAddress address,  ip地址对象
         *                       int port)  端口号
         */
        byte[] bytes = "hello,UDP我来了".getBytes() ;
        int length = bytes.length ;
        InetAddress inetAddress = InetAddress.getByName("192.168.1.5");//无线ip不断变的--->本地回环地址127.0.0.1
        int port = 10086 ;
        DatagramPacket dp = new DatagramPacket(bytes,length,inetAddress,port);
​
        //3)使用发送端的Socket将数据存储数据包中, 发送(本质存储数据包)       
        ds.send(dp) ;
        //4)释放资源
        ds.close() ;
       
    

UDP接受端的代码实现

 //1)创建接收端的Socket对象,绑定端口       
        DatagramSocket ds = new DatagramSocket(10086) ;
​
        //2)创建一个接收容器--->数据包--->自定义字节缓冲区,将发送的数据包
        byte[] bytes = new byte[1024] ;//1024或者1024整数倍
        int length = bytes.length ;
        DatagramPacket dp = new DatagramPacket(bytes,length) ; //将发送端数据缓冲到这个接收容器中
​
        //3)接收,以上面这个接收容器来接收
        ds.receive(dp);
​
        //4)从接收容器中解析数据包的实际内容数据
        //从接收容器中获取public byte[] getData() 实际缓冲区的对象(从上bytes分段取数据)
        byte[] bytes2 = dp.getData();
        //获取里面实际缓冲区的长度
       // public int getLength()
        int length2 = dp.getLength();
        //展示数据---分段取数据,每次从0开始取实际长度
        String msg = new String(bytes2,0,length2) ;
        //数据包里面获取哪一个ip地址发来的--->ip地址字符串形式
        String ip = dp.getAddress().getHostAddress() ;
        System.out.println("data from --->"+ip+",发送内容是:"+msg);
​
        //释放资源
        ds.close();

13.2TCP客户端和服务器端的实现---->安全---可靠连接(使用居多)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值