zoukankan      html  css  js  c++  java
  • 等待唤醒机制,UDP通信和TCP通信

    等待唤醒机制

      通过等待唤醒机制使各个线程能有效的利用资源。

    等待唤醒机制所涉及到的方法:

        wait() :等待,将正在执行的线程释放其执行资格 和 执行权,并存储到线程池中。

        notify():唤醒,唤醒线程池中被wait()的线程,一次唤醒一个,而且是任意的。

       notifyAll(): 唤醒全部:可以将线程池中的所有wait() 线程都唤醒。

      所谓唤醒的意思就是让 线程池中的线程具备执行资格。

      必须注意的是:这些方法都是在 同步中才有效;

          同时这些方法在使用时必须标明所属锁,这样才可以明确出这些方法操作的到底是哪  个锁上的线程。而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中。

    例子:

    代码如下:

    模拟资源类:

    package com.oracle.Resourse;
    
    public class Resourse {
        public String name;
        public String sex;
        public boolean flag = false;
        
    }

    输入线程任务类:

    package com.oracle.Resourse;
    
    public class InputR  implements Runnable{
        private int i=0;
        private Resourse r=new Resourse();
        
        public InputR(Resourse r){
            this.r=r;
        }
        public void run() {
            while(true){
                synchronized (r){
                    if(r.flag){
                        
                        try {
                            r.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    if(i%2==0){
                        r.name="张三";
                        r.sex="男";
                    }else{
                        r.name="LISI";
                        r.sex="NV";
                    }
                    r.flag=true;
                    r.notify();
                }
                i++;
            }
        }
    
    }

    输出线程任务类:

    package com.oracle.Resourse;
    
    public class OutputR   implements Runnable{
    
        private Resourse r=new Resourse();
        public OutputR(Resourse r){
            this.r=r;
        
        }
        public void run() {
            while(true){
                synchronized (r){
                    if(r.flag==false){
                        try {
                            r.wait();
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    System.out.println(r.name+"..."+r.sex);
                    r.flag=false;
                    r.notify();
                    
                }
            }
            
        }
    
    }

    测试类:

    package com.oracle.Resourse;
    
    public class TEST {
    
        public static void main(String[] args) {
            Resourse r=new Resourse();
            InputR in=new InputR(r);
            OutputR out=new OutputR(r)    ;
            Thread t1=new Thread(in);
            Thread t2=new Thread(out);
            t1.start();
            t2.start();
    
    
        }
    
    }

    结果如下:

     InetAddress类

    InetAdderss类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法

    例子:

    public class Example01 {
        public static void main(String[] args) throws Exception {
            InetAddress local = InetAddress.getLocalHost();
            InetAddress remote = InetAddress.getByName("www.oracle.cn");
            System.out.println("本机的IP地址:" + local.getHostAddress());
            System.out.println("oracle的IP地址:" + remote.getHostAddress());
            System.out.println("oracle的主机名为:" + remote.getHostName());
        }
    }

    UDP是一种面向无连接的协议,因此,在通信时发送端和接收端不用建立连接。

    DatagramPacket类

      该类的实例对象就相当于一个集装箱,用于封装UDP通信中发送或者接收的数据。

    构造方法

     

    发送端一定要明确指出数据的目的地(ip地址和端口号),而接收端不需要明确知道数据的来源,只需要接收到数据即可。

    DatagramPacket类中的常用方法

    DatagramSocket类

      DatagramSocket类的作用就类似于码头,使用这个类的实例对象就可以发送和接收DatagramPacket数据包

     构造方法:

      该构造方法用于创建发送端的DatagramSocket对象,在创建DatagramSocket对象时,并没有指定端口号,此时,系统会分配一个没有被其它网络程序所使用的端口号。

      该构造方法既可用于创建接收端的DatagramSocket对象,又可以创建发送端的DatagramSocket对象,在创建接收端的DatagramSocket对象时,必须要指定一个端口号,这样就可以监听指定的端口。

    常用方法:

     例子:

    UDP完成数据的发送:

    package com.oracle.UdpTcp;
    
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    import java.net.InetAddress;
    import java.util.Scanner;
    
    public class UDPSend {
        public static void main(String[] args) throws IOException {
            Scanner sc=new Scanner(System.in    );
            //InetAddress类调用getbyName方法返回一个本类对象
            InetAddress i=InetAddress.getByName("192.168.1.171");
            //创建DatagramSocket对象,
            DatagramSocket ds = new DatagramSocket();
            while(true){
                
                //构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
                
                //定义字节数组来接收发送端的内容
                String mes=sc.next();
                byte[] bytes=mes.getBytes();
                //装包
                DatagramPacket dp = new DatagramPacket(bytes, bytes.length, i, 6666);
                ds.send(dp);    
            }
                    
        }
                
    }

    UDP完成数据的接收:

    package com.oracle.UdpTcp;
    
    import java.io.IOException;
    import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    
    public class UdpS {
            public static void main(String[] args) throws IOException {
                //1,创建DatagramSocket对象,并指定端口号
                DatagramSocket ds = new DatagramSocket(8888);
                //创建接收数据的字节数组
                byte[] bytes =new byte[1024];
                //创建接收数据包
                while(true){
                    DatagramPacket dp = new DatagramPacket(bytes, bytes.length);
                    //接收
                    ds.receive(dp);
                    //获取数据
                    String ip=dp.getAddress().getHostAddress();//获取IP地址
                    int port=dp.getPort();//获取端口号
                    int length = dp.getLength();//获取多少条数据
                    System.out.println(ip+"..."+port+"发送的内容为"+new String(bytes,0,length));
                }
                
    //            ds.close();
            }
    }

    TCP通信

      在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端。

      通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接开始通信。

    ServerSocket类

    构造方法

      使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上(参数port就是端口号)。

    ServerSocket的常用方法:

      ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通信,程序才能继续向下执行。

    Socket类

    构造方法

    常用方法;

    方法声明

    功能描述

    int getPort()

    该方法返回一个int类型对象,该对象是Socket对象与服务器端连接的端口号

    InetAddress getLocalAddress()

    该方法用于获取Socket对象绑定的本地IP地址,并将IP地址封装成InetAddress类型的对象返回

    void close()

    该方法用于关闭Socket连接,结束本次通信。在关闭socket之前,应将与socket相关的所有的输入/输出流全部关闭,这是因为一个良好的程序应该在执行完毕时释放所有的资源

    InputStream getInputStream()

    该方法返回一个InputStream类型的输入流对象,如果该对象是由服务器端的Socket返回,就用于读取客户端发送的数据,反之,用于读取服务器端发送的数据

    OutputStream getOutputStream()

    该方法返回一个OutputStream类型的输出流对象,如果该对象是由服务器端的Socket返回,就用于向客户端发送数据,反之,用于向服务器端发送数据

    例子:

    客户端程序:

    package com.oracle.Tcp;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    
    public class TCPK {
        public static void main(String[] args) throws IOException {
            //创建socket对象,连接服务器
            Socket s=new Socket    ("127.0.0.1",7777    );
            //通过客户端套接字对象Socket对象中的获取字节输出流的方法
            OutputStream out=s.getOutputStream();
            //将数据写向服务器
            out.write("服务器你好".getBytes());
        //接收服务器端的回复
            InputStream in=s.getInputStream();
            byte[] bytes=new byte[1024];
            int len=in.read(bytes);
            System.out.println(new String(bytes,0,len));
            s.close();
    
        }
        
        
    }

    服务器端程序:

    package com.oracle.Tcp;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class TCPS {
    
        public static void main(String[] args) throws IOException {
            //创建服务器套接字
            ServerSocket  ss=new ServerSocket(7777);
            //调用ACCEPT方法与客户端创建链接
            Socket s=ss.accept();
            InputStream in=s.getInputStream();
            byte[] bytes=new byte[1024];
            int len=in.read(bytes);
            System.out.println(new String(bytes,0,len));
            //服务器端给回复
            OutputStream out=s.getOutputStream();
            out.write("收到".getBytes());
    
        }
    
    }

    文件上传案例

      首先编写服务器端程序,用来接收图片。

    package com.oracle.TCPS;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.util.Random;
    
    public class TCPS {
    
        public static void main(String[] args) throws IOException {
            ServerSocket  server=new ServerSocket(7500);//明确端口号
            Socket socket=server.accept();
            //读取文件,明确数据源
            InputStream in=socket.getInputStream();
            //明确目的地
            File file=new File("e:\JPG");
            //判断文件是否存在
            if(!file.exists()){
                file.mkdirs();//没有则创建文件夹
            }
            //域名+毫秒值+6位随机数
    //        随机数
            String num="";
            for(int i=0;i<6;i++){
                num+=new Random().nextInt(10);
            }
            String filename="oracle"+System.currentTimeMillis()+num+".jpg";
            FileOutputStream fos=new FileOutputStream(file+File.separator+filename);
            //复制‘
            int len=0;
            byte[] bytes=new byte[1024];
            while((len=in.read(bytes))!=-1){
                fos.write(bytes,0,len);//往服务器端写
            }
            //回复客户端
            OutputStream out=socket.getOutputStream();
            out.write("上传成功".getBytes());
            fos.close();
            server.close();
            
        }
    
    }

    客户端程序:

    package com.oracle.TCPS;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.net.UnknownHostException;
    
    public class TCPK {
    
        public static void main(String[] args) throws UnknownHostException, IOException {
            //创建socket对象,连接服务器
                    Socket socket=new Socket    ("127.0.0.1",7500    );
                    //获取Socket流中的输出流,功能:用来把数据写到服务器
                    OutputStream out=socket.getOutputStream();
                    //从文件读到客户端
                    FileInputStream fis=new FileInputStream("E:\QQwenjian\1972680739\FileRecv\0601.jpg");
                    //定义字节数组接收文件
                    byte[] bytes=new byte[1024];
                    
                    int len=0;
                    while((len=fis.read(bytes))!=-1){
                        out.write(bytes,0,len);
                    }
                    //客户端发送数据完毕,结束Socket输出流的写入操作,告知服务器端,不再读了
                    socket.shutdownOutput();
    
                    //接收服务器端的回复
                    InputStream in=socket.getInputStream();
                     len=in.read(bytes);
                    System.out.println(new String(bytes,0,len));//将字节数组内容转成字符串打印出来
                    //释放资源
                    fis.close();
                    socket.close();
        }
    
    }

    多文件上传案例

    只需将服务器端代码封装改一下:

    package com.oracle.TCPS;
    
    import java.io.File;
    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.Random;
    
    public class UpLoad implements Runnable{
    
        private Socket socket;
        public UpLoad(Socket socket){
            this.socket=socket;
        }
        public void run() {
            FileOutputStream fos=null;
            
            try{
                //显示哪个客户端Socket连接上了服务器
                InetAddress ipObject = socket.getInetAddress();//得到IP地址对象
                String ip = ipObject.getHostAddress(); //得到IP地址字符串
                System.out.println("小样,抓到你了,连接我!!" + "IP:" + ip);
                
                //读取文件,明确数据源
                InputStream in=socket.getInputStream();
                //明确目的地
                File file=new File("e:\JPG");
                //判断文件是否存在
                if(!file.exists()){
                    file.mkdirs();//没有则创建文件夹
                }
                //域名+毫秒值+6位随机数
                String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(6)+".jpg";
                 fos=new FileOutputStream(file+File.separator+filename);
                //复制,把Socket输入流中的数据,写入目的地的字节输出流中‘
                int len=0;
                byte[] bytes=new byte[1024];
                while((len=in.read(bytes))!=-1){
                    fos.write(bytes,0,len);//往服务器端写
                }
                //回复客户端
                OutputStream out=socket.getOutputStream();
                out.write("上传成功".getBytes());
                }catch (IOException ex){
                    ex.printStackTrace();
                }finally{
                    try {
                        fos.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
    
        
            
        }
        
    }

    测试类:

    package com.oracle.TCPS;
    
    import java.io.IOException;
    import java.net.ServerSocket;
    import java.net.Socket;
    
    public class Demo {
    
        public static void main(String[] args) throws IOException {
            ServerSocket  server=new ServerSocket(7500);//明确端口号
            while(true){
                Socket socket=server.accept();
                new Thread(new UpLoad(socket)).start();//匿名内部类
                
            }
        }
    
    }
  • 相关阅读:
    GTC China 2016观感
    关于OpenGL的绘制上下文
    Voreen(三) 光线投射参数介绍
    分享一些DICOM数据下载网站
    Voreen (二) 入点出点计算
    Voreen (一) GPU Raycast主流程
    GPU渲染和GDI
    程序媛壮志雄心尝试装机,命运多舛壮志未酬失败告终~
    安装Newton版Glance
    安装Newton版Swift,配合keystone认证
  • 原文地址:https://www.cnblogs.com/lzw123-/p/9559078.html
Copyright © 2011-2022 走看看