IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> day_14 -> 正文阅读

[网络协议]day_14

总结:
1.控制线程:
join():等待线程死亡后,其他线程加入执行队列
sleep():当前线程以毫秒数暂停后继续执行
2.线程的分类:守护线程、用户线程

3.线程的生命周期
线程的状态:新建、就绪、运行、阻塞、死亡
4.线程同步
数据安全问题的解决方法:
同步代码块或同步方法:synchronized 关键字 相当于给代码加锁

5.线程的死锁:出现死锁 不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态 无法继续
解决办法:
1 减少同步代码块或同步方法的嵌套
? 2 尽量减少同步资源的定义
? 3 使用专门的算法
6.线程通信
1 等待 wait();唤醒notify / notify All()
2 互斥锁:依次最多只能有一个线程持有锁 lock()获得锁 / unlock()释放锁

7.网络编程
三要素:IP地址、端口、协议
UDP协议:发送数据,接收数据

1 线程控制

voidjoin() 等待这个线程死亡
voidsetDaemon(boolean on) 将此线程标记为 daemon线程或用户线程。
static voidsleep(long millis) 使当前正在执行的线程以指定的毫秒数暂停(暂时停止执行),具体取决于系统定时器和调度程序的精度和准确性。
	t1.join();//等待t1线程死亡,t1 执行结束之后 t2线程在继续执行
	Thread.sleep(1000);// 使线程休眠一定的时间  时间单位为毫秒  时间到达 自动加入执行队列

2 线程的分类

分为:守护线程 和 用户线程

  • 守护线程和用户线程基本上是相同的。唯一的区别就是判断 jvm 何时离开
  • 守护线程是用来服务用户线程的。通过在 start 方法之前调用 thread.setDeamon(true) 可以将一个用户多线程变成守护线程
  • Java的垃圾回收,是一个典型的守护线程
  • 如果 jvm 中都是守护线程,jvm 将退出(用户线程执行结束 守护线程无论是否结束 都将终止执行)

3 线程的生命周期

jdk中使用Thread State定义了线程的状态:

  • 线程状态。线程可以处于以下状态之一:

    • NEW
      尚未启动的线程处于此状态。
    • RUNNABLE
      在Java虚拟机中执行的线程处于此状态。
    • BLOCKED
      被阻塞等待监视器锁定的线程处于此状态。
    • WAITING
      正在等待另一个线程执行特定动作的线程处于此状态。
    • TIMED_WAITING
      正在等待另一个线程执行动作达到指定等待时间的线程处于此状态。
    • TERMINATED
      已退出的线程处于此状态。

线程的状态通常分为5种状态:

  • 新建:当一个Thread类及其子类声明并创建时,此时的线程对象就处于新建状态

  • 就绪:处于新建状态的线程被start后,线程进入CPU的执行队列等待获得CPU的执行权,此时的线程已经具备了运行的条件,只是还未获得CPU的执行权

  • 运行:当就绪的线程获得CPU事物执行权时。就处于运行状态

  • 阻塞:在某种特殊的情况下,被认为挂起或执行输入输出操作时,让出CPU并临时中止自己的执行。此时线程就进入了阻塞状态

  • 死亡:完成了全部工作或线程被提前强制终止,或出现异常导致线程异常结束。

线程状态之间的相互转换
在这里插入图片描述
一个线程一旦死亡,是不可以重新启动的

4 线程同步

案例:卖票

需求:某电影院目前正在上映国产大片,共有100张票。而他有三个售票窗口,请设计一个程序模拟该影院售票

思路:

? 1 定义一个类SellTicket 实习Runnbale接口,定义一个成员变量 private int tickets = 100;

? 2 在SellTicket类中 重写run()。实现卖票:

? A 判断票数是否大于0

? B 售出票之后 票数减一

? C票没有了,也可能还有人来问,所以这个地方使用死循环 让卖票行为一直持续

3 定义一个测试类,实现售票动作

? A 创建SellTicket 类的对象

? B 创建三个Thread类 对象,将SellTicket 类的对象传递给线程 并给线程命名

? C 启动线程

public class SellTicket implements Runnable{
    private int ticktes = 100;
    @Override
    public void run() {
        while(true){
            if(ticktes > 0 ){
                System.out.println(Thread.currentThread().getName()+"正在出售第" + ticktes+"张票");
                ticktes--;
            }
        }
    }
}
public class SellTicketDemo {
    public static void main(String[] args) {
        SellTicket st = new SellTicket();
        //创建三个线程
        Thread t1 = new Thread(st,"1号窗口");
        Thread t2 = new Thread(st,"2号窗口");
        Thread t3 = new Thread(st,"3号窗口");
        //启动线程
        t1.start();
        t2.start();
        t3.start();

    }
}

出现每个窗口销售各自的100张票,实际生活中 售票是需要时间的 ,因此我们售卖一张票的时间为100毫秒

public class SellTicket implements Runnable{
    private int ticktes = 100;
    @Override
    public void run() {
        while(true){
            if(ticktes > 0 ){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"正在出售第" + ticktes+"张票");
                ticktes--;
            }
        }
    }
}

出现负票 和相同号的票
原因线程:执行的顺序是随机的

4.1 解决数据安全问题——同步代码块

出现问题的条件:

  1. 多线程环境
  2. 有共享数据
  3. 有多条语句操作共享数据

如何解决线程安全问题:
基本的思想:让程序没有安全问题的环境

怎么实现呢?

? 把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行。

java提供了解决的方式是使用同步代码块或同步方法:synchronized 相当于给代码加锁

可以用在代码块和方法上 分别称为同步代码块和同步方法:

public class SellTicket implements Runnable{
    private int ticktes = 100;
    private Object obj = new Object();
    @Override
    public void run() {
        while(true){
            synchronized (obj){// 给一下代码加锁  括号中需要一个所对象
                if(ticktes > 0 ){
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()+"正在出售第" + ticktes+"张票");
                    ticktes--;
                }
            }
        }
    }
}

在同步代码块中 ,任意对象都可以充当所对象 一般情况下使用this

4.2 解决数据安全问题——实现方法

在方法的声明上添加synchronized关键字

public class SellTicket implements Runnable{
    private int ticktes = 100;
   // private String s = "abc";
    @Override
    public  void run() {
        while(true){
                sellTicket();
            }
    }
    public synchronized void sellTicket(){//这才是真正存在数据安全的操作  这个就称为同步方法  这里锁对象时this
        if(ticktes > 0 ){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"正在出售第" + ticktes+"张票");
            ticktes--;
        }
    }
}

静态同步方法

public class SellTicket implements Runnable{
    private static int ticktes = 100;
   // private String s = "abc";
    @Override
    public  void run() {
        while(true){
                sellTicket();
            }
    }
    public static synchronized void sellTicket(){
        if(ticktes > 0 ){
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName()+"正在出售第" + ticktes+"张票");
            ticktes--;
        }
    }
}

静态方法的同步代码块

public class SellTicket implements Runnable{
    private static int ticktes = 100;// 共享数据应该是静态的
   // private String s = "abc";
    @Override
    public  void run() {
        while(true){
                sellTicket();
            }
    }
    public static   void sellTicket(){//这才是真正存在数据安全的操作  这个就称为同步方法  这里锁对象时this
       synchronized(SellTicket.class){
           if(ticktes > 0 ){
               try {
                   Thread.sleep(100);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               System.out.println(Thread.currentThread().getName()+"正在出售第" + ticktes+"张票");
               ticktes--;
           }
       }
   }

静态的同步方法或者静态方法中的同步代码块的所对象是类名.class对象

单例设计模式:懒汉式设计存在线程安全问题

public class Singleton {
    private static  Singleton instance;
    private Singleton(){
        
    }
    public static  Singleton getInstance(){
        if( instance == null){
            synchronized (Singleton.class){
                if(instance ==null){
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
public class SingletonTest {
    public static void main(String[] args) {
        Singleton s1 = Singleton.getInstance();
        Singleton s2 = Singleton.getInstance();
        System.out.println(s1 == s2);

    }
}

4.6 线程安全的类

  • StringBuffer 线程安全的可变字符序列

  • StringBuilder 线程不安全的可变字符序列

  • Vector 线程同步的

  • HashTable 线程同步的 是一个哈希表的实现

在实际使用时,如果不需要线程安全的实现,推荐使用与之功能相同的 但是线程不同步的实现

5 线程的死锁的演示

死锁是我们需要规避的问题

不同的线程分别占用对方所需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就行成了线程死锁

出现死锁 不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态 无法继续

public class DeadLockDemo {
    public static void main(String[] args) {
        final  StringBuilder  s1 = new StringBuilder();
        final  StringBuilder s2 = new StringBuilder();
        new Thread(){
            @Override
            public void run() {
                synchronized (s1){
                    s2.append("A");
                    synchronized (s2){
                        s2.append("B");
                        System.out.println(s1);
                        System.out.println(s2);
                    }
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                synchronized (s2){
                    s2.append("C");
                    synchronized (s1){
                        s1.append("D");
                        System.out.println(s2);
                        System.out.println(s1);
                    }
                }
            }
        }.start();
    }
}

死锁问题的出现是一个概率时间。

死锁问题的解决:

? 1 减少同步代码块或同步方法的嵌套

? 2 尽量减少同步资源的定义

? 3 使用专门的算法

练习:

银行有一个账户,有两个储户分别向同一个账户存3000,每次存1000元,存3次,每次存完打印账户余额。

该程序是否存在安全问题,如果存在 如何解决?

提示:

? 1 明确那些代码是多线程运行的代码,就是需要写入run方法

? 2 明确那些数据是共享数据

? 3 明确多下称运行代码中的那些语句操作了共享数据

6 线程通信

6.1 什么时候需要线程通信

多个线程并发执行,在默认情况下CPU随机切换线程,如果我们希望他们有规律的执行,就需要使用线程通信。

6.2 线程间如何通信

如果线程需要等待 就要调用wait()
如果要唤醒一个等待的线程 那么就使用notify() / notifyAll()

voidwait() 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。
voidnotify() 唤醒正在等待对象监视器的单个线程。
voidnotifyAll() 唤醒正在等待对象监视器的所有线程。
voidwait(long timeout) 导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过。
public class ThreadWait {
    public static void main(String[] args) {
        ThreadWait tw = new ThreadWait();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                   tw.print1();
                }

            }
        }).start();
        new Thread(){
            @Override
            public void run() {
                while(true){
                    tw.print2() ;
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                while(true){
                    tw.print3() ;
                }
            }
        }.start();
    }
    public   synchronized   void  print1(){
        notifyAll();
        System.out.print("中");
        System.out.print("北");
        System.out.print("大");
        System.out.print("学");
        System.out.println();
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public   synchronized   void  print2(){
        notifyAll();
        System.out.print("塔");
        System.out.print("里");
        System.out.print("木");
        System.out.print("大");
        System.out.print("学");
        System.out.println();
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public   synchronized   void  print3(){
        notifyAll();
        System.out.print("青");
        System.out.print("岛");
        System.out.print("大");
        System.out.print("学");
        System.out.println();
        try {
            wait();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

三个线程间的通信:想要按照顺序依次执行,notify和wait做不到

6.3 互斥锁

互斥锁:最多只能有1个线程持有锁

锁是用于通过多个线程控制对共享资源的访问的工具。 通常,锁提供对共享资源的独占访问:一次只能有一个线程可以获取锁,并且对共享资源的所有访问都要求首先获取锁

voidlock() 获得锁。
voidunlock() 释放锁。

Interface Lock 可以使用的实现类 ReentrantLock

  • 一个可重入互斥Lock具有与使用synchronized方法和语句访问的隐式监视锁相同的基本行为和语义,但具有扩展功能。

Condition

voidawait() 导致当前线程等到发信号或 interrupted
booleanawait(long time, TimeUnit unit) 使当前线程等待直到发出信号或中断,或指定的等待时间过去。
voidsignal() 唤醒一个等待线程。
voidsignalAll() 唤醒所有等待线程。

不同的线程需要使用不同的 Condition 这样就能区分唤醒额时候唤醒的是那个线程

public class ThreadLock {
    public static void main(String[] args) {
        ThreadLock tw = new ThreadLock();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    tw.print1();
                }

            }
        }).start();
        new Thread(){
            @Override
            public void run() {
                while(true){
                    tw.print2() ;
                }
            }
        }.start();
        new Thread(){
            @Override
            public void run() {
                while(true){
                    tw.print3() ;
                }
            }
        }.start();
    }
    // 创建Lock锁对象
    Lock lock = new ReentrantLock();
    //创建锁使用的条件
    Condition c1 = lock.newCondition();
    Condition c2 = lock.newCondition();
    Condition c3 = lock.newCondition();
    // 创建一个唤醒标志
    int  flag = 1;
    public      void  print1(){
        lock.lock();//给当前代码上锁
        if(flag != 1){
            try {
                c1.await();//当前线程处于等待
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.print("中");
        System.out.print("北");
        System.out.print("大");
        System.out.print("学");
        System.out.println();
        flag = 2;
        c2.signal();//唤醒c2
        lock.unlock();//释放锁
    }
    public     void  print2(){
       lock.lock();
       if(flag != 2){
           try {
               c2.await();
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
        System.out.print("塔");
        System.out.print("里");
        System.out.print("木");
        System.out.print("大");
        System.out.print("学");
        System.out.println();
         flag =3;
         c3.signal();
         lock.unlock();
    }
    public     void  print3(){
         lock.lock();
         if(flag != 3){
             try {
                 c3.await();
             } catch (InterruptedException e) {
                 e.printStackTrace();
             }
         }
        System.out.print("青");
        System.out.print("岛");
        System.out.print("大");
        System.out.print("学");
        System.out.println();
         flag =1;
         c1.signal();
         lock.unlock();
    }
}

6.4 生产者消费者案例

案例需求:

? 生产者和消费者案例中包含几个对象:

? 1 奶箱(box) 定义一个变量 表示奶箱中奶的数量 提供存储牛奶和获取牛奶的方法

? 2 生产者(product) 线程 重写run 调用存储牛奶的方法

? 3消费者(Customer) 线程 重写run 调用获取牛奶的方法

测试:

? 1 创建奶箱对象 这是共享数据区

? 2生产者对象,把奶箱作为参数传递给生产者。 调用存储的方法

? 3创建消费者 把奶箱作为参数传递给消费者。 调用获取的方法

? 4 创建线程 启动线程

public class Box {
    private  int  milk;//表示奶箱中牛奶的数量
    private boolean state = false; //表示奶箱的状态  false  表示空  true 满
    public synchronized void put(int milk){
        if(state){// 表示奶箱中有牛奶
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 如果没有牛奶 就生产牛奶
        this.milk = milk;
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("生产者将第" + milk + "瓶牛奶放入奶箱");
        //生产完毕之后 修改奶箱的状态
        this.state = true;
        // 唤醒消费者来消费
        notifyAll();
    }
    public synchronized void  get(){
        // 如果没有牛奶 就等待生产
        if(!state){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        // 有牛奶 就消费
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("用户消费了第" + milk +"瓶牛奶");
        state = false;
        //唤醒生产者生产
        notifyAll();
    }
}

package cn.lanqiao;

public class Product  implements  Runnable{
    private  Box box;
    public Product(Box box){
        this.box = box;
    }
    @Override
    public void run() {
        for(int i = 0; i <=30 ; i++){
            box.put(i);
        }
    }
}

package cn.lanqiao;

public class Customer implements  Runnable{
    private Box box;
    public Customer(Box box){
        this.box = box;
    }
    @Override
    public void run() {
        while(true){
            box.get();
        }
    }
}

public class BoxTest {
    public static void main(String[] args) {
        Box box = new Box();//这是生产者和消费者的共享数据
        //创建生产者
        Product p = new Product(box);
        // 创建消费者
        Customer c = new Customer(box);
        //创建线程
        Thread t1= new Thread(p);
        Thread t2 = new Thread(c);
        t1.start();
        t2.start();
    }
}

生产者消费者模型的作用是什么?
1通过平衡生产者的生产能力和消费者消费能力来提升整个系统的运行效率
2 解耦

多线程的学习重点:

  1. 线程的创建方式
  2. 线程的生命周期(线程的五种状态的转换)
  3. 线程同步
  4. 线程通信

7 网络编程

7.1 计算机的网络

网络: 是指将地理位置不同的具有地理功能的计算机及其外部设备 通过通信线路连接起来,在网络操作系统 网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统

网络编程 :在网络协议下,实现网络互联的不同计算机上运行的程序见可以进行数据交换

7.2 网络编程的三要素:

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

端口:就是通过唯一标识锁定的设备上的应用程序的标识

协议:对数据的传输格式 传输速率 传输的步骤等做的统一规定,将这种规则称为通信协议,双方都必须遵守,才能完成数据交换。
常见的通信协议:UDP和TCP

7.3 InetAddress

static InetAddressgetByName(String host) 确定主机名称的IP地址。
StringgetHostName() 获取此IP地址的主机名。
StringgetHostAddress() 返回文本显示中的IP地址字符串
static InetAddressgetLocalHost() 返回本地主机的地址。
    public static void main(String[] args) throws UnknownHostException {
        // 所有与网络编程先关的类 都位于java.net包下
        InetAddress address = InetAddress.getLocalHost();
        System.out.println(address.getHostName());//DESKTOP-RK7RI6L
        InetAddress  address1 = InetAddress.getByName("10.96.106.111");
        System.out.println(address1.getHostAddress());// 获取IP地址字符串
    }

7.4 端口

端口:是程序在设备上的标识号
端口号:使用两个字节表示的整数,取值范围0—65535 ,其中0–1023之间的端口主要用于一些网络服务和应用。在自己写网络协议时尽量使用1024以上的端口

7.5 协议

UDP协议: 用户数据报协议
是无连接的通信协议,在数据传输时,数据的发送端和接收端不建立逻辑链接

优点:UDP协议消耗资源少,通信的效率高。

TCP:传输控制协议
是面向链接的通信协议,在传输数据之前。必须在发送端和接收端之间建立逻辑链接,然后才能传输数据。可以提供两台设备之间的可靠无差错通信

TCP协议区分发送端和接收端

TCP协议的链接的建立:

  • TCP的链接需要经过三次”握手“
  • TCP协议断开需要经过四次”挥手“
    在这里插入图片描述

7.6 UDP协议通信程序

UDP是属于一种不可靠的协议,在通信的两端需要建一个Socket(网络套接字)对象。都是这两个Socket,只是发送和接收数据的对象,因此对于基于UDP协议的通信而言。没有所谓的客户端和服务器的概念

DataGramSocket 基于UDP 协议的Socket

  • 此类表示用于发送和接收数据报数据包的套接字。
  • 数据报套接字是分组传送服务的发送或接收点。

构造方法:

DatagramSocket() 构造数据报套接字并将其绑定到本地主机上的任何可用端口。
protectedDatagramSocket(DatagramSocketImpl impl) 使用指定的DatagramSocketImpl创建一个未绑定的数据报套接字。
DatagramSocket(int port) 构造数据报套接字并将其绑定到本地主机上的指定端口。
DatagramSocket(int port, InetAddress laddr) 创建一个数据报套接字,绑定到指定的本地地址。
DatagramSocket(SocketAddress bindaddr) 创建一个数据报套接字,绑定到指定的本地套接字地址。
voidreceive(DatagramPacket p) 从此套接字接收数据报包。
-----------------------------------------------------------
voidsend(DatagramPacket p) 从此套接字发送数据报包。

DataGramPacket 表示数据报包,用于实现无连接分组传送服务

DatagramPacket(byte[] buf, int length) 构造一个 DatagramPacket用于接收长度的数据包 length
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。
DatagramPacket(byte[] buf, int offset, int length) 构造一个 DatagramPacket用于接收长度的分组 length ,指定偏移到缓冲器中。
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 构造用于发送长度的分组数据报包 length具有偏移 ioffset指定主机上到指定的端口号。
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造用于发送长度的分组数据报包 length具有偏移 ioffset指定主机上到指定的端口号。
DatagramPacket(byte[] buf, int length, SocketAddress address) 构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号。

发送数据的步骤:

  1. 创建发送端的Socket对象 DataGramSocket
  2. 创建数据,并将数据打包
  3. 调用DataGramSocket 的 send 方法
  4. 关闭发送端 Close
public class SendSocket {
    public static void main(String[] args) throws IOException {
//        1 创建发送端的Socket对象 DataGramSocket
        DatagramSocket  ds = new DatagramSocket();
//	2 创建数据  并将数据打包  DatagramPacket
        byte[] packet= "hello  UDP".getBytes(StandardCharsets.UTF_8);
        DatagramPacket dp = new DatagramPacket(packet,packet.length, InetAddress.getByName("127.0.0.1"),10086);
//	3 调用DataGramSocket 的send方法  发送数据
     ds.send(dp);
//	4 关闭发送端  close
        ds.close();
    }
}

接收数据的步骤:

  1. 创建发送端的Socket对象 DataGramSocket
  2. 创建一个数据报包 用于接收数据DataGramPacket
  3. 调用DATa Gram Socket的reveive接收
  4. 解析数据报包,把信息输出
  5. 关闭接收端口
public class ReceiveSocket {
    public static void main(String[] args) throws IOException {
        //创建接收端的Socket 对象
        DatagramSocket ds = new DatagramSocket(12503);
        //创建数据报包 接收数据
       while (true) {
           byte[] data = new byte[1024];
           DatagramPacket dp = new DatagramPacket(data, data.length);
           //调用DataGramSocket 的receive接收
           ds.receive(dp);
           //解析数据报包,输出信息
           System.out.println("接收发送端的数据:" + new String(dp.getData(), 0, dp.getLength()));
       }
    }
}

7.6.1 UDP协议通信的练习

需求:

UDP发送数据,接收来自键盘录入,直到输入的数据是666/bye 发送结束

UDP接收数据,因为接收端你不知道发送端何时发送数据 所以采用死循环 持续等待

// 发送数据  数据来自键盘
public class SendSokect2 {
    public static void main(String[] args) throws IOException {
        DatagramSocket ds = new DatagramSocket();
        //封装键盘录入的数据
        BufferedReader br  = new BufferedReader(new InputStreamReader(System.in));
        String line;
        while((line = br.readLine())!=null){
            //判断读入的数据是否是结束标记
            if("bye".equals(line)){
                break;
            }
            //创建数据 并打包
            byte[] data = line.getBytes(StandardCharsets.UTF_8);
            DatagramPacket dp = new DatagramPacket(data,data.length, InetAddress.getByName("127.0.0.1"),10086);
            ds.send(dp);
        }
        //关闭发送端
        ds.close();
    }
}

//接收数据
public class ReciveSocket2 {
    public static void main(String[] args) throws IOException {
        System.out.println("接收端启动成功:");
        DatagramSocket ds = new DatagramSocket(10086);
        while(true){
            //创建接收数据的包
            byte[] data = new byte[1024];
            DatagramPacket dp = new DatagramPacket(data,data.length);
            ds.receive(dp);
            //解析数据
            System.out.println("接收到发送端的数据:" +new String(dp.getData(),0,dp.getLength()));
        }
    }
}
  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-01 14:49:27  更:2021-08-01 14:51:38 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 17:49:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码