• Java基础00-网络编程29


    1. 网络编程入门

    1.1 网络编程概述

       

      

    1.2 网络编程三要素

      

    1.3 IP地址

      

    在命令提示符中使用

      
    1.4 InetAddress的使用

      
    代码示例:

    public class InetAddressDemo {
        // InetAddress
        // 此类表示Internet协议(IP) 地址
        public static void main(String[] args) throws UnknownHostException {
            // public static InetAddress getByName (String host):
            // 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址,推荐是使用IP地址
            //InetAddress address = InetAddress.getByName("WxW");
            InetAddress address = InetAddress.getByName("192.168.0.105");
    
            // public String getHostName ():获取此IP地址的主机名
            String hostName = address.getHostName();
            System.out.println(hostName);
    
            // public String getHostAddress (): 返回文本显示中的IP地址字符串
            String hostAddress = address.getHostAddress();
            System.out.println(hostAddress);
        }
    }

    运行结果:

      

    代码示例:

    public class InetAddressTest {
        public static void main(String[] args) throws UnknownHostException {
            System.out.println(InetAddress.getLocalHost());//LAPTOP-VEKHRDDR/192.168.240.1
            System.out.println(InetAddress.getLocalHost().getHostName());//LAPTOP-VEKHRDDR
            System.out.println(InetAddress.getLocalHost().getHostAddress());//192.168.240.1
            System.out.println(InetAddress.getByName("192.168.3.11"));//输出:/192.168.3.11
            System.out.println(InetAddress.getByName("192.168.3.11").getHostName());//LAPTOP-VEKHRDDR
            System.out.println(InetAddress.getByName("192.168.3.11").getHostAddress());//192.168.3.11
            System.out.println(InetAddress.getByName("LAPTOP-VEKHRDDR"));//LAPTOP-VEKHRDDR/192.168.240.1
            System.out.println(InetAddress.getByName("LAPTOP-VEKHRDDR").getHostName());//LAPTOP-VEKHRDDR
            System.out.println(InetAddress.getByName("LAPTOP-VEKHRDDR").getHostAddress());//192.168.240.1
        }
    }

    运行结果:

      

    1.5 端口

     

    1.6 协议

      

       

    三次握手

       

     

    2. UDP通信程序

    2.1 UDP通信原理

      

    2.2 UDP发送数据

      

    代码示例:

    创建发送端

    public class SendDemo {
        public static void main(String[] args) throws IOException {
            // 1:创建发送端的Socket对象(DatagramSocket)
            // DatagramSocket ()构造数据报套接字并将其绑定到本地主机上的任何可用端口
            DatagramSocket ds = new DatagramSocket();
    
            // 2:创建数据,并把数据打包
            // DatagramPacket (byte[] buf, int Length, InetAddress address, int port)
            // 构造一个数据包,发送长度为length的数据 包到指定主机上的指定端口号。
            byte[] bys = "hello,udp,我来了".getBytes();
            int length = bys.length;
            InetAddress destAddress = InetAddress.getByName("192.168.0.105");
            int port = 10086;
            DatagramPacket dp = new DatagramPacket(bys, length, destAddress, port);
    
            // 上面的步骤也可以写成这样
    //        DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.0.105"), 10086);
    
            // 3:调用DatagramSocket对象的方法发送数据
            // void send (DatagramPacket p)从此套接字发送数据报包
            ds.send(dp);
    
            // 4:关闭发送端
            ds.close();
    
        }
    }

    运行结果:
    运行后并没有输出结果,因为还没有写接收端

    2.3 UDP接收数据

      
    代码示例:

    创建接受端public class ReceiveDemo {    public static void main(String[] args) throws IOException {

    // 1:创建接收端的Socket对象(DatagramSocket )
            // DatagramSocket (int port)构造数据报套接字并将其绑定到本地主机上的指定端口
            DatagramSocket ds = new DatagramSocket(10086);
    
            // 2:创建一个数据包,用于接收数据
            // DatagramPacket (byte[] buf, int length) 构造一个 DatagramPacket用于 接收长度为Length数据包
            byte[] bys = new byte[1024];
            DatagramPacket dp = new DatagramPacket(bys, bys.length);
    
            // 3:调用DatagramSocket对象的方法接收数据
            ds.receive(dp);
    
            // 4:解析数据包,并把数据在控制台显示
            // byte[] getData() 返回数据缓仲区
            byte[] datas = dp.getData();
            // int getLength () 返回要发送的数据的长度或接收到的数据的长度
            int len = dp.getLength();
            String dataString = new String(datas, 0, len); // 这样写是为了让输出的数据正好而不多余。
            System.out.println("数据是:" + dataString);
    
            // 上面的步骤也可以这样写
    //        System.out.println("数据是:" + new String(dp.getData(), 0, dp.getLength()));
         
         
    String ip = dp.getAddress().getHostAddress();
         System.out.println("收到"+ip+"发来的消息");
    // 5:关闭接收端
            ds.close();
    
        }
    }

    运行结果:
    运行时要先运行接收端再运行发送端,这样就就可以在接收端的控制台上看见接收到的数据了。

      
    2.4 UDP通信程序练习

      
    代码示例:

    UDP发送端

    /*
        UDP发送数据:
            数据来自于键盘录入,直到输入的数据是886,发送数据结束
     */
    public class SendDemo {
        public static void main(String[] args) throws IOException {
            // 创建发送端的Socket对象(DatagramSocket )
            DatagramSocket ds = new DatagramSocket();
    
            // 自己封装键盘录入数据
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            String line;
            while ((line = br.readLine()) != null) {
                // 输入的数据的886,发送数据接收
                if ("886".equals(line)) {
                    break;
                }
    
                // 创建数据,并把数据打包
                byte[] bys = line.getBytes();
                DatagramPacket dp = new DatagramPacket(bys, bys.length, InetAddress.getByName("192.168.0.105"), 12345);
    
                // 调用DatagramSocket对象发送程序
                ds.send(dp);
            }
            // 关闭发送端
            ds.close();
    
        }
    } 

    UDP接收端 

    /*
        UDP接收数据:
            因为接收端不知道发送端什么时候停止发送,故采用死循环接收
    */
    public class ReceiveDemo {
        public static void main(String[] args) throws IOException {
            // 创建接收端的Socket对象(DatagramSocket)
            DatagramSocket ds = new DatagramSocket(12345);
    
            while (true) {
                // 创建一个数据包,用于接收数据
                byte[] bys = new byte[1024];
                DatagramPacket dp = new DatagramPacket(bys, bys.length);
    
                // 调用DatagramSocket对象的方法接收数据
                ds.receive(dp);
           String data = new String(dp.getData(), 0, dp.getLength());
           // 解析数据包,并把数据在控制台显示 
           System.out.println("数据是:" + data);
        }

    // 因为是采用死循环所以不需要关闭接收端
    }
    }

    运行结果:

      

      


    输入886结束接收

      

    还可以开启多个发送数据窗口,每个窗口都可以发送数据,互不影响。

    3. TCP通信程序

    3.1 TCP通信原理

      

    3.2 TCP发送数据

      
    代码示例:

    //TCP发送数据
    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            // 1:创建客户端的Socket对象(Socket)
            // Socket (InetAddress address, int port)创建流套接字并将其连接到指定IP地址的指定端口号
    //        Socket s = new Socket(InetAddress.getByName("192.168.0.105"), 1000);
            // Socket (String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号
            Socket s = new Socket("192.168.0.105", 1000);// 这两个方法做的是同一件事
    
            // 2:获取输出流,写数据
            // OutputStream getOutputStream () 返回此套接字的输出流
            OutputStream os = s.getOutputStream();
            os.write("Hello,tcp,我来了".getBytes());
    
            // 3:释放资源
            s.close();
    
        }
    }

    3.3 TCP接收数据

      
    代码示例:

    //TCP接收数据
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            // 1:创建服务器端的Socket对象(ServerSocket)
            // ServerSocket (int port)创建绑定到指定端口的服务器套接字
            ServerSocket ss = new ServerSocket(10000);
    
            // Socket accept() 侦听要连接到此套接字并接受它
            Socket s = ss.accept();
    
            // 2:获取输入流,读数据,并把数据显示在控制台
            InputStream is = s.getInputStream();
            byte[] bys = new byte[1024];
            int len;
            while ((len = is.read(bys)) != -1) {
                System.out.println("数据是:" + new String(bys, 0, len));
            }
    
            // 3:释放资源
            ss.close();
        }
    }

    运行结果:
    先开启接收端再开启发送端

      
    3.4 TCP通信程序练习

    3.4.1 练习1:发送数据接收反馈,接受数据发出反馈

      
    代码示例:

    创建客户端:

    /*
     * 客户端:发送数据,接收服务器反馈 
     */
    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            // 创建客户端的Socket对象(Socket)
            Socket s = new Socket(" ", 1000);
    
            // 获取输出流,写数据
            OutputStream os = s.getOutputStream();
            os.write("hello,tcp,我来了".getBytes());
    
            // 接收服务器反馈
            InputStream is = s.getInputStream();
            byte[] bys = new byte[1024];
            int len = is.read(bys);
            String data = new String(bys, 0, len);
            System.out.println("客户端:" + data);
    
            // 释放资源
            s.close();
    
        }
    }

    创建服务器端:

    /*
     * 服务器:接收数据,给出反馈
     */
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            // 创建服务器端的Socket对象(ServerSocket)
            ServerSocket ss = new ServerSocket(1000);
    
            // 监听客户端连接,返回一个Socket对象
            Socket s = ss.accept();
    
            // 获取输入流,读数据,并把数据显示在控制台
            InputStream is = s.getInputStream();
            byte[] bys = new byte[1024];
            int len = is.read(bys);
            String data = new String(bys, 0, len);
            System.out.println("服务器:" + data);
    
            // 给出反馈
            OutputStream os = s.getOutputStream();
            os.write("数据已收到".getBytes());
    
            // 释放资源
            ss.close();
    
        }
    }

    运行结果:
    先打开服务器,然后等待客户端连接。

      

       

    3.4.2 练习2:用键盘录入数据

      
    代码示例:

    创建客户端:

    /*
     * 客户端:数据来自于键盘录入,直到输入的数据是886,发送数据结束
     */
    public class ClientDemo {
    
        public static void main(String[] args) throws IOException {
            // 创建客户点Socket对象
            Socket s = new Socket("192.168.0.105", 10000);
    
            // 数据来自于键盘录入,直到输入的数据是886,发送数据结束
            // 使用自己包装的键盘录入
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            // 封装输出流对象,将输出流封装成缓存流
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    
            String line;
            while ((line = br.readLine()) != null) {
    
                if ("886".equals(line)) {
                    break;
                }
    
                // 获取输出流对象
    //            OutputStream os = s.getOutputStream();
    //            os.write(line.getBytes());
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
            // 释放资源
            s.close();
        }
    }

    创建服务器端:

    /*
     * 服务器:接收到的数据在控制台输出
     */
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            // 创建服务器Socket对象
            ServerSocket ss = new ServerSocket(10000);
    
            // 监听客户端的连接,返回一个对应的Socket对象
            Socket s = ss.accept();
    
            // 获取输入流,将输出流封装成缓存流
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String line;
            while ((line = br.readLine()) != null) {
                System.out.println(line);
            }
            // 释放资源
            ss.close();
        }
    }

    运行结果:
    先运行服务器端再运行客户端,在客户端输入数据发送到服务器端。

       

      

      

    3.4.3 练习3:将键盘录入的数据写入文本文件

      
    代码示例:

    创建客户端:
    客户端和练习2是一样的

    /*
     * 客户端:数据来自于键盘录入,直到输入的数据是886,发送数据结束
     */
    public class ClientDemo {
    
        public static void main(String[] args) throws IOException {
            // 创建客户点Socket对象
            Socket s = new Socket("192.168.0.105", 10000);
    
            // 数据来自于键盘录入,直到输入的数据是886,发送数据结束
            // 使用自己包装的键盘录入
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            // 封装输出流对象
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    
            String line;
            while ((line = br.readLine()) != null) {
    
                if ("886".equals(line)) {
                    break;
                }
    
                // 获取输出流对象
    //            OutputStream os = s.getOutputStream();
    //            os.write(line.getBytes());
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
            // 释放资源
            s.close();
        }
    }

    创建服务端: 

    /*
     * 服务器:接收到的数据写入文本文件
     */
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            // 创建服务端Socket对象
            ServerSocket ss = new ServerSocket(10000);
    
            // 监听客户端,返回一个对应的Socket对象
            Socket s = ss.accept();
    
            // 接收数据
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    
            // 把数据写入文本文件
            BufferedWriter bw = new BufferedWriter(new FileWriter("s.text"));
            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
            // 释放资源
            bw.close();
            ss.close();
    
        }
    }

    运行结果:
    先运行服务器再运行客户端,再客户端写数据传入服务器再写入文本文件。

      

       

    3.4.4 练习4:数据来自文本,发送到服务器再写入文本(上传接收)

      
    代码示例:

    被复制文件是练习3的s.text
    创建客户端:

    /*
     * 客户端:数据来自于文本文件
     */
    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            // 创建客户端Socket对象
            Socket s = new Socket("192.168.0.105", 10000);
    
            // 封装文本文件的数据
            BufferedReader br = new BufferedReader(new FileReader("s.text"));
    
            // 封装输出流写数据
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    
            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            // 释放资源
            br.close();
            s.close();
    
        }
    }

    创建服务器:
    服务器和练习3是一样的

    /*
     * 服务器:接收到的数据写入文本文件
     */
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            // 创建服务端Socket对象
            ServerSocket ss = new ServerSocket(10000);
    
            // 监听客户端,返回一个对应的Socket对象
            Socket s = ss.accept();
    
            // 接收数据
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    
            // 把数据写入文本文件
            BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.text"));
            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
            // 释放资源
            bw.close();
            ss.close();
    
        }
    }

    运行结果:
    先运行服务器端再运行客户端。

      
    3.4.5 练习5:在练习4的基础上加上服务器反馈

      

    按照常规的方法会出现问题

      
    代码示例:

    接收服务器的反馈最重要的是在客户端加入结束标签shutdownOutput(),这样才能让服务器端知道你已经结束输出数据了。

    创建客户端:

    /*
     * 客户端:数据来自于文本文件
     */
    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            // 创建客户端Socket对象
            Socket s = new Socket("192.168.0.105", 10000);
    
            // 封装文本文件的数据
            BufferedReader br = new BufferedReader(new FileReader("s.text"));
    
            // 封装输出流写数据
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    
            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            // 定义结束标签
            // void shutdownOutput() 禁用此套接字的输出流。
            s.shutdownOutput();
    
            // 接收反馈
            BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String data = brClient.readLine();
            System.out.println("服务器的反馈:" + data);
    
            // 释放资源
            br.close();
            s.close();
        }
    }

    创建服务端:

    /*
     * 服务器:接收到的数据写入文本文件
     */
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            // 创建服务端Socket对象
            ServerSocket ss = new ServerSocket(10000);
    
            // 监听客户端,返回一个对应的Socket对象
            Socket s = ss.accept();
    
            // 接收数据
            BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    
            // 把数据写入文本文件
            BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.text"));
            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            // 给出反馈
            BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            bwServer.write("文件上传成功!");
            bwServer.newLine();
            bwServer.flush();
    
            // 释放资源
            bw.close();
            ss.close();
        }
    }

    运行结果:

      
    3.4.6 练习6:利用多线程使服务器接收多个客户端的文件

      
    代码示例:

    创建客户端类: 

    /*
     * 客户端:数据来自于文本文件
     */
    public class ClientDemo {
        public static void main(String[] args) throws IOException {
            // 创建客户端Socket对象
            Socket s = new Socket("192.168.0.105", 10000);
    
            // 封装文本文件的数据
            BufferedReader br = new BufferedReader(new FileReader("s.text"));
    
            // 封装输出流写数据
            BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
    
            String line;
            while ((line = br.readLine()) != null) {
                bw.write(line);
                bw.newLine();
                bw.flush();
            }
    
            // 定义结束标签
            // void shutdownOutput() 禁用此套接字的输出流。
            s.shutdownOutput();
    
            // 接收反馈
            BufferedReader brClient = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String data = brClient.readLine();
            System.out.println("服务器的反馈:" + data);
    
            // 释放资源
            br.close();
            s.close();
        }
    }

    创建服务器类:

    /*
     * 服务器:接收到的数据写入文本文件,给出反馈,代码用线程进行封装,为每一个客户端开启一个线程
     */
    public class ServerDemo {
        public static void main(String[] args) throws IOException {
            // 创建服务端Socket对象
            ServerSocket ss = new ServerSocket(10000);
    
            while (true) {
                // 监听客户端,返回一个对应的Socket对象
                Socket s = ss.accept();
                // 为每一个客户端开启一个线程
                new Thread(new ServerTherad(s)).start();
            }
        }
    }

    创建线程类:

    public class ServerTherad implements Runnable {
    
        private Socket s;
    
        public ServerTherad(Socket s) {
            this.s = s;
        }
    
        @Override
        public void run() {
            try {
                // 接收数据
                BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
    
                // 把数据写入文本文件
                // 解决命名冲突问题
                int count = 0;
                File file = new File("Copy[" + count + "].text");
                while (file.exists()) {
                    count++;
                    file = new File("Copy[" + count + "].text");
                }
                BufferedWriter bw = new BufferedWriter(new FileWriter(file));
                
                String line;
                while ((line = br.readLine()) != null) {
                    bw.write(line);
                    bw.newLine();
                    bw.flush();
                }
    
                // 给出反馈
                BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
                bwServer.write("文件上传成功!");
                bwServer.newLine();
                bwServer.flush();
    
                // 释放资源
                bw.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    运行结果:
    先运行服务器再运行客户端,不过这次可以运行多次客户端,可以复制对个文件夹,而且不会重名。
    第一次

      

      


    第二次

      

      

  • 相关阅读:
    超能陆战队之大白的制作过程
    React生命周期
    系统环境变量的解析
    React函数组件
    Node Js模块讲解
    封装读取文件(node js)
    思维导图
    《Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases》论文总结
    《Object Storage on CRAQ: High-throughput chain replication for read-mostly workloads》论文总结
    《 ZooKeeper : Wait-free coordination for Internet-scale systems 》论文研读
  • 原文地址:https://www.cnblogs.com/ajing2018/p/14684683.html
Copyright © 2020-2023  润新知